Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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/. */
7 // For connections that are not processed on the socket transport thread, we do
8 // NOT use the async logic described below. Instead, we authenticate the
9 // certificate on the thread that the connection's I/O happens on,
10 // synchronously. This allows us to do certificate verification for blocking
11 // (not non-blocking) sockets and sockets that have their I/O processed on a
12 // thread other than the socket transport service thread. Also, we DO NOT
13 // support blocking sockets on the socket transport service thread at all.
14 //
15 // During certificate authentication, we call CERT_PKIXVerifyCert or
16 // CERT_VerifyCert. These functions may make zero or more HTTP requests
17 // for OCSP responses, CRLs, intermediate certificates, etc. Our fetching logic
18 // for these requests processes them on the socket transport service thread.
19 //
20 // If the connection for which we are verifying the certificate is happening
21 // on the socket transport thread (the usually case, at least for HTTP), then
22 // if our cert auth hook were to call the CERT_*Verify* functions directly,
23 // there would be a deadlock: The CERT_*Verify* function would cause an event
24 // to be asynchronously posted to the socket transport thread, and then it
25 // would block the socket transport thread waiting to be notified of the HTTP
26 // response. However, the HTTP request would never actually be processed
27 // because the socket transport thread would be blocked and so it wouldn't be
28 // able process HTTP requests. (i.e. Deadlock.)
29 //
30 // Consequently, when we are asked to verify a certificate on the socket
31 // transport service thread, we must always call the CERT_*Verify* cert
32 // functions on another thread. To accomplish this, our auth cert hook
33 // dispatches a SSLServerCertVerificationJob to a pool of background threads,
34 // and then immediatley return SECWouldBlock to libssl. These jobs are where
35 // the CERT_*Verify* functions are actually called.
36 //
37 // When our auth cert hook returns SECWouldBlock, libssl will carry on the
38 // handshake while we validate the certificate. This will free up the socket
39 // transport thread so that HTTP requests--in particular, the OCSP/CRL/cert
40 // requests needed for cert verification as mentioned above--can be processed.
41 //
42 // Once the CERT_*Verify* function returns, the cert verification job
43 // dispatches a SSLServerCertVerificationResult to the socket transport thread;
44 // the SSLServerCertVerificationResult will notify libssl that the certificate
45 // authentication is complete. Once libssl is notified that the authentication
46 // is complete, it will continue the SSL handshake (if it hasn't already
47 // finished) and it will begin allowing us to send/receive data on the
48 // connection.
49 //
50 // Timeline of events (for connections managed by the socket transport service):
51 //
52 // * libssl calls SSLServerCertVerificationJob::Dispatch on the socket
53 // transport thread.
54 // * SSLServerCertVerificationJob::Dispatch queues a job
55 // (instance of SSLServerCertVerificationJob) to its background thread
56 // pool and returns.
57 // * One of the background threads calls CERT_*Verify*, which may enqueue
58 // some HTTP request(s) onto the socket transport thread, and then
59 // blocks that background thread waiting for the responses and/or timeouts
60 // or errors for those requests.
61 // * Once those HTTP responses have all come back or failed, the
62 // CERT_*Verify* function returns a result indicating that the validation
63 // succeeded or failed.
64 // * If the validation succeeded, then a SSLServerCertVerificationResult
65 // event is posted to the socket transport thread, and the cert
66 // verification thread becomes free to verify other certificates.
67 // * Otherwise, a CertErrorRunnable is posted to the socket transport thread
68 // and then to the main thread (blocking both, see CertErrorRunnable) to
69 // do cert override processing and bad cert listener notification. Then
70 // the cert verification thread becomes free to verify other certificates.
71 // * After processing cert overrides, the CertErrorRunnable will dispatch a
72 // SSLServerCertVerificationResult event to the socket transport thread to
73 // notify it of the result of the override processing; then it returns,
74 // freeing up the main thread.
75 // * The SSLServerCertVerificationResult event will either wake up the
76 // socket (using SSL_RestartHandshakeAfterServerCert) if validation
77 // succeeded or there was an error override, or it will set an error flag
78 // so that the next I/O operation on the socket will fail, causing the
79 // socket transport thread to close the connection.
80 //
81 // Cert override processing must happen on the main thread because it accesses
82 // the nsICertOverrideService, and that service must be accessed on the main
83 // thread because some extensions (Selenium, in particular) replace it with a
84 // Javascript implementation, and chrome JS must always be run on the main
85 // thread.
86 //
87 // SSLServerCertVerificationResult must be dispatched to the socket transport
88 // thread because we must only call SSL_* functions on the socket transport
89 // thread since they may do I/O, because many parts of nsNSSSocketInfo (the
90 // subclass of TransportSecurityInfo used when validating certificates during
91 // an SSL handshake) and the PSM NSS I/O layer are not thread-safe, and because
92 // we need the event to interrupt the PR_Poll that may waiting for I/O on the
93 // socket for which we are validating the cert.
95 #include "SSLServerCertVerification.h"
97 #include <cstring>
99 #include "pkix/pkixtypes.h"
100 #include "CertVerifier.h"
101 #include "CryptoTask.h"
102 #include "ExtendedValidation.h"
103 #include "NSSCertDBTrustDomain.h"
104 #include "nsIBadCertListener2.h"
105 #include "nsICertOverrideService.h"
106 #include "nsISiteSecurityService.h"
107 #include "nsNSSComponent.h"
108 #include "nsNSSCleaner.h"
109 #include "nsRecentBadCerts.h"
110 #include "nsNSSIOLayer.h"
111 #include "nsNSSShutDown.h"
113 #include "mozilla/Assertions.h"
114 #include "mozilla/Mutex.h"
115 #include "mozilla/Telemetry.h"
116 #include "mozilla/unused.h"
117 #include "nsIThreadPool.h"
118 #include "nsNetUtil.h"
119 #include "nsXPCOMCIDInternal.h"
120 #include "nsComponentManagerUtils.h"
121 #include "nsServiceManagerUtils.h"
122 #include "PSMRunnable.h"
123 #include "SharedSSLState.h"
124 #include "nsContentUtils.h"
126 #include "ssl.h"
127 #include "secerr.h"
128 #include "secport.h"
129 #include "sslerr.h"
130 #include "ocsp.h"
132 #ifdef PR_LOGGING
133 extern PRLogModuleInfo* gPIPNSSLog;
134 #endif
136 namespace mozilla { namespace psm {
138 namespace {
140 NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
142 NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
143 NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
145 // do not use a nsCOMPtr to avoid static initializer/destructor
146 nsIThreadPool* gCertVerificationThreadPool = nullptr;
148 // We avoid using a mutex for the success case to avoid lock-related
149 // performance issues. However, we do use a lock in the error case to simplify
150 // the code, since performance in the error case is not important.
151 Mutex* gSSLVerificationTelemetryMutex = nullptr;
153 // We add a mutex to serialize PKCS11 database operations
154 Mutex* gSSLVerificationPK11Mutex = nullptr;
156 } // unnamed namespace
158 // Called when the socket transport thread starts, to initialize the SSL cert
159 // verification thread pool. By tying the thread pool startup/shutdown directly
160 // to the STS thread's lifetime, we ensure that they are *always* available for
161 // SSL connections and that there are no races during startup and especially
162 // shutdown. (Previously, we have had multiple problems with races in PSM
163 // background threads, and the race-prevention/shutdown logic used there is
164 // brittle. Since this service is critical to things like downloading updates,
165 // we take no chances.) Also, by doing things this way, we avoid the need for
166 // locks, since gCertVerificationThreadPool is only ever accessed on the socket
167 // transport thread.
168 void
169 InitializeSSLServerCertVerificationThreads()
170 {
171 gSSLVerificationTelemetryMutex = new Mutex("SSLVerificationTelemetryMutex");
172 gSSLVerificationPK11Mutex = new Mutex("SSLVerificationPK11Mutex");
173 // TODO: tuning, make parameters preferences
174 // XXX: instantiate nsThreadPool directly, to make this more bulletproof.
175 // Currently, the nsThreadPool.h header isn't exported for us to do so.
176 nsresult rv = CallCreateInstance(NS_THREADPOOL_CONTRACTID,
177 &gCertVerificationThreadPool);
178 if (NS_FAILED(rv)) {
179 NS_WARNING("Failed to create SSL cert verification threads.");
180 return;
181 }
183 (void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
184 (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
185 (void) gCertVerificationThreadPool->SetThreadLimit(5);
186 (void) gCertVerificationThreadPool->SetName(NS_LITERAL_CSTRING("SSL Cert"));
187 }
189 // Called when the socket transport thread finishes, to destroy the thread
190 // pool. Since the socket transport service has stopped processing events, it
191 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
192 // down the SSL cert verification infrastructure. Also, the STS will not
193 // dispatch many SSL verification result events at this point, so any pending
194 // cert verifications will (correctly) fail at the point they are dispatched.
195 //
196 // The other shutdown race condition that is possible is a race condition with
197 // shutdown of the nsNSSComponent service. We use the
198 // nsNSSShutdownPreventionLock where needed (not here) to prevent that.
199 void StopSSLServerCertVerificationThreads()
200 {
201 if (gCertVerificationThreadPool) {
202 gCertVerificationThreadPool->Shutdown();
203 NS_RELEASE(gCertVerificationThreadPool);
204 }
205 if (gSSLVerificationTelemetryMutex) {
206 delete gSSLVerificationTelemetryMutex;
207 gSSLVerificationTelemetryMutex = nullptr;
208 }
209 if (gSSLVerificationPK11Mutex) {
210 delete gSSLVerificationPK11Mutex;
211 gSSLVerificationPK11Mutex = nullptr;
212 }
213 }
215 namespace {
217 void
218 LogInvalidCertError(TransportSecurityInfo* socketInfo,
219 PRErrorCode errorCode,
220 ::mozilla::psm::SSLErrorMessageType errorMessageType)
221 {
222 nsString message;
223 socketInfo->GetErrorLogMessage(errorCode, errorMessageType, message);
224 if (!message.IsEmpty()) {
225 nsContentUtils::LogSimpleConsoleError(message, "SSL");
226 }
227 }
229 // Dispatched to the STS thread to notify the infoObject of the verification
230 // result.
231 //
232 // This will cause the PR_Poll in the STS thread to return, so things work
233 // correctly even if the STS thread is blocked polling (only) on the file
234 // descriptor that is waiting for this result.
235 class SSLServerCertVerificationResult : public nsRunnable
236 {
237 public:
238 NS_DECL_NSIRUNNABLE
240 SSLServerCertVerificationResult(TransportSecurityInfo* infoObject,
241 PRErrorCode errorCode,
242 Telemetry::ID telemetryID = Telemetry::HistogramCount,
243 uint32_t telemetryValue = -1,
244 SSLErrorMessageType errorMessageType =
245 PlainErrorMessage);
247 void Dispatch();
248 private:
249 const RefPtr<TransportSecurityInfo> mInfoObject;
250 public:
251 const PRErrorCode mErrorCode;
252 const SSLErrorMessageType mErrorMessageType;
253 const Telemetry::ID mTelemetryID;
254 const uint32_t mTelemetryValue;
255 };
257 class CertErrorRunnable : public SyncRunnableBase
258 {
259 public:
260 CertErrorRunnable(const void* fdForLogging,
261 nsIX509Cert* cert,
262 TransportSecurityInfo* infoObject,
263 PRErrorCode defaultErrorCodeToReport,
264 uint32_t collectedErrors,
265 PRErrorCode errorCodeTrust,
266 PRErrorCode errorCodeMismatch,
267 PRErrorCode errorCodeExpired,
268 uint32_t providerFlags)
269 : mFdForLogging(fdForLogging), mCert(cert), mInfoObject(infoObject),
270 mDefaultErrorCodeToReport(defaultErrorCodeToReport),
271 mCollectedErrors(collectedErrors),
272 mErrorCodeTrust(errorCodeTrust),
273 mErrorCodeMismatch(errorCodeMismatch),
274 mErrorCodeExpired(errorCodeExpired),
275 mProviderFlags(providerFlags)
276 {
277 }
279 virtual void RunOnTargetThread();
280 RefPtr<SSLServerCertVerificationResult> mResult; // out
281 private:
282 SSLServerCertVerificationResult* CheckCertOverrides();
284 const void* const mFdForLogging; // may become an invalid pointer; do not dereference
285 const nsCOMPtr<nsIX509Cert> mCert;
286 const RefPtr<TransportSecurityInfo> mInfoObject;
287 const PRErrorCode mDefaultErrorCodeToReport;
288 const uint32_t mCollectedErrors;
289 const PRErrorCode mErrorCodeTrust;
290 const PRErrorCode mErrorCodeMismatch;
291 const PRErrorCode mErrorCodeExpired;
292 const uint32_t mProviderFlags;
293 };
295 // A probe value of 1 means "no error".
296 uint32_t
297 MapCertErrorToProbeValue(PRErrorCode errorCode)
298 {
299 switch (errorCode)
300 {
301 case SEC_ERROR_UNKNOWN_ISSUER: return 2;
302 case SEC_ERROR_CA_CERT_INVALID: return 3;
303 case SEC_ERROR_UNTRUSTED_ISSUER: return 4;
304 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: return 5;
305 case SEC_ERROR_UNTRUSTED_CERT: return 6;
306 case SEC_ERROR_INADEQUATE_KEY_USAGE: return 7;
307 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: return 8;
308 case SSL_ERROR_BAD_CERT_DOMAIN: return 9;
309 case SEC_ERROR_EXPIRED_CERTIFICATE: return 10;
310 }
311 NS_WARNING("Unknown certificate error code. Does MapCertErrorToProbeValue "
312 "handle everything in PRErrorCodeToOverrideType?");
313 return 0;
314 }
316 SECStatus
317 MozillaPKIXDetermineCertOverrideErrors(CERTCertificate* cert,
318 const char* hostName, PRTime now,
319 PRErrorCode defaultErrorCodeToReport,
320 /*out*/ uint32_t& collectedErrors,
321 /*out*/ PRErrorCode& errorCodeTrust,
322 /*out*/ PRErrorCode& errorCodeMismatch,
323 /*out*/ PRErrorCode& errorCodeExpired)
324 {
325 MOZ_ASSERT(cert);
326 MOZ_ASSERT(hostName);
327 MOZ_ASSERT(collectedErrors == 0);
328 MOZ_ASSERT(errorCodeTrust == 0);
329 MOZ_ASSERT(errorCodeMismatch == 0);
330 MOZ_ASSERT(errorCodeExpired == 0);
332 // Assumes the error prioritization described in mozilla::pkix's
333 // BuildForward function. Also assumes that CERT_VerifyCertName was only
334 // called if CertVerifier::VerifyCert succeeded.
335 switch (defaultErrorCodeToReport) {
336 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
337 case SEC_ERROR_CA_CERT_INVALID:
338 case SEC_ERROR_UNKNOWN_ISSUER:
339 {
340 collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED;
341 errorCodeTrust = defaultErrorCodeToReport;
343 SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, now, false);
344 if (validity == secCertTimeUndetermined) {
345 PR_SetError(defaultErrorCodeToReport, 0);
346 return SECFailure;
347 }
348 if (validity != secCertTimeValid) {
349 collectedErrors |= nsICertOverrideService::ERROR_TIME;
350 errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
351 }
352 break;
353 }
355 case SEC_ERROR_EXPIRED_CERTIFICATE:
356 collectedErrors = nsICertOverrideService::ERROR_TIME;
357 errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
358 break;
360 case SSL_ERROR_BAD_CERT_DOMAIN:
361 collectedErrors = nsICertOverrideService::ERROR_MISMATCH;
362 errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
363 break;
365 case 0:
366 NS_ERROR("No error code set during certificate validation failure.");
367 PR_SetError(PR_INVALID_STATE_ERROR, 0);
368 return SECFailure;
370 default:
371 PR_SetError(defaultErrorCodeToReport, 0);
372 return SECFailure;
373 }
375 if (defaultErrorCodeToReport != SSL_ERROR_BAD_CERT_DOMAIN) {
376 if (CERT_VerifyCertName(cert, hostName) != SECSuccess) {
377 if (PR_GetError() != SSL_ERROR_BAD_CERT_DOMAIN) {
378 PR_SetError(defaultErrorCodeToReport, 0);
379 return SECFailure;
380 }
382 collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
383 errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
384 }
385 }
387 return SECSuccess;
388 }
390 SSLServerCertVerificationResult*
391 CertErrorRunnable::CheckCertOverrides()
392 {
393 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p][%p] top of CheckCertOverrides\n",
394 mFdForLogging, this));
395 // "Use" mFdForLogging in non-PR_LOGGING builds, too, to suppress
396 // clang's -Wunused-private-field build warning for this variable:
397 unused << mFdForLogging;
399 if (!NS_IsMainThread()) {
400 NS_ERROR("CertErrorRunnable::CheckCertOverrides called off main thread");
401 return new SSLServerCertVerificationResult(mInfoObject,
402 mDefaultErrorCodeToReport);
403 }
405 int32_t port;
406 mInfoObject->GetPort(&port);
408 nsCString hostWithPortString;
409 hostWithPortString.AppendASCII(mInfoObject->GetHostNameRaw());
410 hostWithPortString.AppendLiteral(":");
411 hostWithPortString.AppendInt(port);
413 uint32_t remaining_display_errors = mCollectedErrors;
415 nsresult nsrv;
417 // Enforce Strict-Transport-Security for hosts that are "STS" hosts:
418 // connections must be dropped when there are any certificate errors
419 // (STS Spec section 7.3).
420 bool strictTransportSecurityEnabled = false;
421 nsCOMPtr<nsISiteSecurityService> sss
422 = do_GetService(NS_SSSERVICE_CONTRACTID, &nsrv);
423 if (NS_SUCCEEDED(nsrv)) {
424 nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS,
425 mInfoObject->GetHostNameRaw(),
426 mProviderFlags,
427 &strictTransportSecurityEnabled);
428 }
429 if (NS_FAILED(nsrv)) {
430 return new SSLServerCertVerificationResult(mInfoObject,
431 mDefaultErrorCodeToReport);
432 }
434 if (!strictTransportSecurityEnabled) {
435 nsCOMPtr<nsICertOverrideService> overrideService =
436 do_GetService(NS_CERTOVERRIDE_CONTRACTID);
437 // it is fine to continue without the nsICertOverrideService
439 uint32_t overrideBits = 0;
441 if (overrideService)
442 {
443 bool haveOverride;
444 bool isTemporaryOverride; // we don't care
445 nsCString hostString(mInfoObject->GetHostName());
446 nsrv = overrideService->HasMatchingOverride(hostString, port,
447 mCert,
448 &overrideBits,
449 &isTemporaryOverride,
450 &haveOverride);
451 if (NS_SUCCEEDED(nsrv) && haveOverride)
452 {
453 // remove the errors that are already overriden
454 remaining_display_errors &= ~overrideBits;
455 }
456 }
458 if (!remaining_display_errors) {
459 // This can double- or triple-count one certificate with multiple
460 // different types of errors. Since this is telemetry and we just
461 // want a ballpark answer, we don't care.
462 if (mErrorCodeTrust != 0) {
463 uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeTrust);
464 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
465 }
466 if (mErrorCodeMismatch != 0) {
467 uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeMismatch);
468 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
469 }
470 if (mErrorCodeExpired != 0) {
471 uint32_t probeValue = MapCertErrorToProbeValue(mErrorCodeExpired);
472 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, probeValue);
473 }
475 // all errors are covered by override rules, so let's accept the cert
476 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
477 ("[%p][%p] All errors covered by override rules\n",
478 mFdForLogging, this));
479 return new SSLServerCertVerificationResult(mInfoObject, 0);
480 }
481 } else {
482 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
483 ("[%p][%p] Strict-Transport-Security is violated: untrusted "
484 "transport layer\n", mFdForLogging, this));
485 }
487 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
488 ("[%p][%p] Certificate error was not overridden\n",
489 mFdForLogging, this));
491 // Ok, this is a full stop.
492 // First, deliver the technical details of the broken SSL status.
494 // Try to get a nsIBadCertListener2 implementation from the socket consumer.
495 nsCOMPtr<nsISSLSocketControl> sslSocketControl = do_QueryInterface(
496 NS_ISUPPORTS_CAST(nsITransportSecurityInfo*, mInfoObject));
497 if (sslSocketControl) {
498 nsCOMPtr<nsIInterfaceRequestor> cb;
499 sslSocketControl->GetNotificationCallbacks(getter_AddRefs(cb));
500 if (cb) {
501 nsCOMPtr<nsIBadCertListener2> bcl = do_GetInterface(cb);
502 if (bcl) {
503 nsIInterfaceRequestor* csi
504 = static_cast<nsIInterfaceRequestor*>(mInfoObject);
505 bool suppressMessage = false; // obsolete, ignored
506 nsrv = bcl->NotifyCertProblem(csi, mInfoObject->SSLStatus(),
507 hostWithPortString, &suppressMessage);
508 }
509 }
510 }
512 nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
513 nsCOMPtr<nsIRecentBadCerts> recentBadCertsService;
514 if (certdb) {
515 bool isPrivate = mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE;
516 certdb->GetRecentBadCerts(isPrivate, getter_AddRefs(recentBadCertsService));
517 }
519 if (recentBadCertsService) {
520 NS_ConvertUTF8toUTF16 hostWithPortStringUTF16(hostWithPortString);
521 recentBadCertsService->AddBadCert(hostWithPortStringUTF16,
522 mInfoObject->SSLStatus());
523 }
525 // pick the error code to report by priority
526 PRErrorCode errorCodeToReport = mErrorCodeTrust ? mErrorCodeTrust
527 : mErrorCodeMismatch ? mErrorCodeMismatch
528 : mErrorCodeExpired ? mErrorCodeExpired
529 : mDefaultErrorCodeToReport;
531 SSLServerCertVerificationResult* result =
532 new SSLServerCertVerificationResult(mInfoObject,
533 errorCodeToReport,
534 Telemetry::HistogramCount,
535 -1,
536 OverridableCertErrorMessage);
538 LogInvalidCertError(mInfoObject,
539 result->mErrorCode,
540 result->mErrorMessageType);
542 return result;
543 }
545 void
546 CertErrorRunnable::RunOnTargetThread()
547 {
548 MOZ_ASSERT(NS_IsMainThread());
550 mResult = CheckCertOverrides();
552 MOZ_ASSERT(mResult);
553 }
555 // Converts a PRErrorCode into one of
556 // nsICertOverrideService::ERROR_UNTRUSTED,
557 // nsICertOverrideService::ERROR_MISMATCH,
558 // nsICertOverrideService::ERROR_TIME
559 // if the given error code is an overridable error.
560 // If it is not, then 0 is returned.
561 uint32_t
562 PRErrorCodeToOverrideType(PRErrorCode errorCode)
563 {
564 switch (errorCode)
565 {
566 case SEC_ERROR_UNKNOWN_ISSUER:
567 case SEC_ERROR_UNTRUSTED_ISSUER:
568 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
569 case SEC_ERROR_UNTRUSTED_CERT:
570 case SEC_ERROR_INADEQUATE_KEY_USAGE:
571 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
572 case SEC_ERROR_CA_CERT_INVALID:
573 // We group all these errors as "cert not trusted"
574 return nsICertOverrideService::ERROR_UNTRUSTED;
575 case SSL_ERROR_BAD_CERT_DOMAIN:
576 return nsICertOverrideService::ERROR_MISMATCH;
577 case SEC_ERROR_EXPIRED_CERTIFICATE:
578 return nsICertOverrideService::ERROR_TIME;
579 default:
580 return 0;
581 }
582 }
584 SECStatus
585 NSSDetermineCertOverrideErrors(CertVerifier& certVerifier,
586 CERTCertificate* cert,
587 const SECItem* stapledOCSPResponse,
588 TransportSecurityInfo* infoObject,
589 PRTime now,
590 PRErrorCode defaultErrorCodeToReport,
591 /*out*/ uint32_t& collectedErrors,
592 /*out*/ PRErrorCode& errorCodeTrust,
593 /*out*/ PRErrorCode& errorCodeMismatch,
594 /*out*/ PRErrorCode& errorCodeExpired)
595 {
596 MOZ_ASSERT(cert);
597 MOZ_ASSERT(infoObject);
598 MOZ_ASSERT(defaultErrorCodeToReport != 0);
599 MOZ_ASSERT(collectedErrors == 0);
600 MOZ_ASSERT(errorCodeTrust == 0);
601 MOZ_ASSERT(errorCodeMismatch == 0);
602 MOZ_ASSERT(errorCodeExpired == 0);
604 if (defaultErrorCodeToReport == 0) {
605 NS_ERROR("No error code set during certificate validation failure.");
606 PR_SetError(PR_INVALID_STATE_ERROR, 0);
607 return SECFailure;
608 }
610 // We only allow overrides for certain errors. Return early if the error
611 // is not one of them. This is to avoid doing revocation fetching in the
612 // case of OCSP stapling and probably for other reasons.
613 if (PRErrorCodeToOverrideType(defaultErrorCodeToReport) == 0) {
614 PR_SetError(defaultErrorCodeToReport, 0);
615 return SECFailure;
616 }
618 PLArenaPool* log_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
619 PLArenaPoolCleanerFalseParam log_arena_cleaner(log_arena);
620 if (!log_arena) {
621 NS_ERROR("PORT_NewArena failed");
622 return SECFailure; // PORT_NewArena set error code
623 }
625 CERTVerifyLog* verify_log = PORT_ArenaZNew(log_arena, CERTVerifyLog);
626 if (!verify_log) {
627 NS_ERROR("PORT_ArenaZNew failed");
628 return SECFailure; // PORT_ArenaZNew set error code
629 }
630 CERTVerifyLogContentsCleaner verify_log_cleaner(verify_log);
631 verify_log->arena = log_arena;
633 // We ignore the result code of the cert verification (i.e. VerifyCert's rv)
634 // Either it is a failure, which is expected, and we'll process the
635 // verify log below.
636 // Or it is a success, then a domain mismatch is the only
637 // possible failure.
638 // XXX TODO: convert to VerifySSLServerCert
639 // XXX TODO: get rid of error log
640 certVerifier.VerifyCert(cert, certificateUsageSSLServer,
641 now, infoObject, infoObject->GetHostNameRaw(),
642 0, stapledOCSPResponse, nullptr, nullptr, verify_log);
644 // Check the name field against the desired hostname.
645 if (CERT_VerifyCertName(cert, infoObject->GetHostNameRaw()) != SECSuccess) {
646 collectedErrors |= nsICertOverrideService::ERROR_MISMATCH;
647 errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
648 }
650 CERTVerifyLogNode* i_node;
651 for (i_node = verify_log->head; i_node; i_node = i_node->next) {
652 uint32_t overrideType = PRErrorCodeToOverrideType(i_node->error);
653 // If this isn't an overridable error, set the error and return.
654 if (overrideType == 0) {
655 PR_SetError(i_node->error, 0);
656 return SECFailure;
657 }
658 collectedErrors |= overrideType;
659 if (overrideType == nsICertOverrideService::ERROR_UNTRUSTED) {
660 if (errorCodeTrust == 0) {
661 errorCodeTrust = i_node->error;
662 }
663 } else if (overrideType == nsICertOverrideService::ERROR_MISMATCH) {
664 if (errorCodeMismatch == 0) {
665 errorCodeMismatch = i_node->error;
666 }
667 } else if (overrideType == nsICertOverrideService::ERROR_TIME) {
668 if (errorCodeExpired == 0) {
669 errorCodeExpired = i_node->error;
670 }
671 } else {
672 MOZ_CRASH("unexpected return value from PRErrorCodeToOverrideType");
673 }
674 }
676 return SECSuccess;
677 }
679 // Returns null with the error code (PR_GetError()) set if it does not create
680 // the CertErrorRunnable.
681 CertErrorRunnable*
682 CreateCertErrorRunnable(CertVerifier& certVerifier,
683 PRErrorCode defaultErrorCodeToReport,
684 TransportSecurityInfo* infoObject,
685 CERTCertificate* cert,
686 const SECItem* stapledOCSPResponse,
687 const void* fdForLogging,
688 uint32_t providerFlags,
689 PRTime now)
690 {
691 MOZ_ASSERT(infoObject);
692 MOZ_ASSERT(cert);
694 uint32_t collected_errors = 0;
695 PRErrorCode errorCodeTrust = 0;
696 PRErrorCode errorCodeMismatch = 0;
697 PRErrorCode errorCodeExpired = 0;
699 SECStatus rv;
700 switch (certVerifier.mImplementation) {
701 case CertVerifier::classic:
702 #ifndef NSS_NO_LIBPKIX
703 case CertVerifier::libpkix:
704 #endif
705 rv = NSSDetermineCertOverrideErrors(certVerifier, cert, stapledOCSPResponse,
706 infoObject, now,
707 defaultErrorCodeToReport,
708 collected_errors, errorCodeTrust,
709 errorCodeMismatch, errorCodeExpired);
710 break;
712 case CertVerifier::mozillapkix:
713 rv = MozillaPKIXDetermineCertOverrideErrors(cert,
714 infoObject->GetHostNameRaw(),
715 now, defaultErrorCodeToReport,
716 collected_errors,
717 errorCodeTrust,
718 errorCodeMismatch,
719 errorCodeExpired);
720 break;
722 default:
723 MOZ_CRASH("unexpected CertVerifier implementation");
724 PR_SetError(defaultErrorCodeToReport, 0);
725 return nullptr;
727 }
728 if (rv != SECSuccess) {
729 return nullptr;
730 }
732 RefPtr<nsNSSCertificate> nssCert(nsNSSCertificate::Create(cert));
733 if (!nssCert) {
734 NS_ERROR("nsNSSCertificate::Create failed");
735 PR_SetError(SEC_ERROR_NO_MEMORY, 0);
736 return nullptr;
737 }
739 if (!collected_errors) {
740 // This will happen when CERT_*Verify* only returned error(s) that are
741 // not on our whitelist of overridable certificate errors.
742 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] !collected_errors: %d\n",
743 fdForLogging, static_cast<int>(defaultErrorCodeToReport)));
744 PR_SetError(defaultErrorCodeToReport, 0);
745 return nullptr;
746 }
748 infoObject->SetStatusErrorBits(*nssCert, collected_errors);
750 return new CertErrorRunnable(fdForLogging,
751 static_cast<nsIX509Cert*>(nssCert.get()),
752 infoObject, defaultErrorCodeToReport,
753 collected_errors, errorCodeTrust,
754 errorCodeMismatch, errorCodeExpired,
755 providerFlags);
756 }
758 // When doing async cert processing, we dispatch one of these runnables to the
759 // socket transport service thread, which blocks the socket transport
760 // service thread while it waits for the inner CertErrorRunnable to execute
761 // CheckCertOverrides on the main thread. CheckCertOverrides must block events
762 // on both of these threads because it calls TransportSecurityInfo::GetInterface(),
763 // which may call nsHttpConnection::GetInterface() through
764 // TransportSecurityInfo::mCallbacks. nsHttpConnection::GetInterface must always
765 // execute on the main thread, with the socket transport service thread
766 // blocked.
767 class CertErrorRunnableRunnable : public nsRunnable
768 {
769 public:
770 CertErrorRunnableRunnable(CertErrorRunnable* certErrorRunnable)
771 : mCertErrorRunnable(certErrorRunnable)
772 {
773 }
774 private:
775 NS_IMETHOD Run()
776 {
777 nsresult rv = mCertErrorRunnable->DispatchToMainThreadAndWait();
778 // The result must run on the socket transport thread, which we are already
779 // on, so we can just run it directly, instead of dispatching it.
780 if (NS_SUCCEEDED(rv)) {
781 rv = mCertErrorRunnable->mResult ? mCertErrorRunnable->mResult->Run()
782 : NS_ERROR_UNEXPECTED;
783 }
784 return rv;
785 }
786 RefPtr<CertErrorRunnable> mCertErrorRunnable;
787 };
789 class SSLServerCertVerificationJob : public nsRunnable
790 {
791 public:
792 // Must be called only on the socket transport thread
793 static SECStatus Dispatch(const RefPtr<SharedCertVerifier>& certVerifier,
794 const void* fdForLogging,
795 TransportSecurityInfo* infoObject,
796 CERTCertificate* serverCert,
797 SECItem* stapledOCSPResponse,
798 uint32_t providerFlags,
799 PRTime time);
800 private:
801 NS_DECL_NSIRUNNABLE
803 // Must be called only on the socket transport thread
804 SSLServerCertVerificationJob(const RefPtr<SharedCertVerifier>& certVerifier,
805 const void* fdForLogging,
806 TransportSecurityInfo* infoObject,
807 CERTCertificate* cert,
808 SECItem* stapledOCSPResponse,
809 uint32_t providerFlags,
810 PRTime time);
811 const RefPtr<SharedCertVerifier> mCertVerifier;
812 const void* const mFdForLogging;
813 const RefPtr<TransportSecurityInfo> mInfoObject;
814 const mozilla::pkix::ScopedCERTCertificate mCert;
815 const uint32_t mProviderFlags;
816 const PRTime mTime;
817 const TimeStamp mJobStartTime;
818 const ScopedSECItem mStapledOCSPResponse;
819 };
821 SSLServerCertVerificationJob::SSLServerCertVerificationJob(
822 const RefPtr<SharedCertVerifier>& certVerifier, const void* fdForLogging,
823 TransportSecurityInfo* infoObject, CERTCertificate* cert,
824 SECItem* stapledOCSPResponse, uint32_t providerFlags, PRTime time)
825 : mCertVerifier(certVerifier)
826 , mFdForLogging(fdForLogging)
827 , mInfoObject(infoObject)
828 , mCert(CERT_DupCertificate(cert))
829 , mProviderFlags(providerFlags)
830 , mTime(time)
831 , mJobStartTime(TimeStamp::Now())
832 , mStapledOCSPResponse(SECITEM_DupItem(stapledOCSPResponse))
833 {
834 }
836 // This function assumes that we will only use the SPDY connection coalescing
837 // feature on connections where we have negotiated SPDY using NPN. If we ever
838 // talk SPDY without having negotiated it with SPDY, this code will give wrong
839 // and perhaps unsafe results.
840 //
841 // Returns SECSuccess on the initial handshake of all connections, on
842 // renegotiations for any connections where we did not negotiate SPDY, or on any
843 // SPDY connection where the server's certificate did not change.
844 //
845 // Prohibit changing the server cert only if we negotiated SPDY,
846 // in order to support SPDY's cross-origin connection pooling.
847 static SECStatus
848 BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
849 CERTCertificate* serverCert)
850 {
851 // Get the existing cert. If there isn't one, then there is
852 // no cert change to worry about.
853 nsCOMPtr<nsIX509Cert> cert;
854 nsCOMPtr<nsIX509Cert2> cert2;
856 RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
857 if (!status) {
858 // If we didn't have a status, then this is the
859 // first handshake on this connection, not a
860 // renegotiation.
861 return SECSuccess;
862 }
864 status->GetServerCert(getter_AddRefs(cert));
865 cert2 = do_QueryInterface(cert);
866 if (!cert2) {
867 NS_NOTREACHED("every nsSSLStatus must have a cert"
868 "that implements nsIX509Cert2");
869 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
870 return SECFailure;
871 }
873 // Filter out sockets that did not neogtiate SPDY via NPN
874 nsAutoCString negotiatedNPN;
875 nsresult rv = infoObject->GetNegotiatedNPN(negotiatedNPN);
876 NS_ASSERTION(NS_SUCCEEDED(rv),
877 "GetNegotiatedNPN() failed during renegotiation");
879 if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN,
880 NS_LITERAL_CSTRING("spdy/")))
881 return SECSuccess;
883 // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
884 if (NS_FAILED(rv)) {
885 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
886 ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call."
887 " Assuming spdy.\n"));
888 }
890 // Check to see if the cert has actually changed
891 ScopedCERTCertificate c(cert2->GetCert());
892 NS_ASSERTION(c, "very bad and hopefully impossible state");
893 bool sameCert = CERT_CompareCerts(c, serverCert);
894 if (sameCert)
895 return SECSuccess;
897 // Report an error - changed cert is confirmed
898 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
899 ("SPDY Refused to allow new cert during renegotiation\n"));
900 PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0);
901 return SECFailure;
902 }
904 SECStatus
905 AuthCertificate(CertVerifier& certVerifier, TransportSecurityInfo* infoObject,
906 CERTCertificate* cert, SECItem* stapledOCSPResponse,
907 uint32_t providerFlags, PRTime time)
908 {
909 MOZ_ASSERT(infoObject);
910 MOZ_ASSERT(cert);
912 SECStatus rv;
914 // TODO: Remove this after we switch to mozilla::pkix as the
915 // only option
916 if (certVerifier.mImplementation == CertVerifier::classic) {
917 if (stapledOCSPResponse) {
918 CERTCertDBHandle* handle = CERT_GetDefaultCertDB();
919 rv = CERT_CacheOCSPResponseFromSideChannel(handle, cert, PR_Now(),
920 stapledOCSPResponse,
921 infoObject);
922 if (rv != SECSuccess) {
923 // Due to buggy servers that will staple expired OCSP responses
924 // (see for example http://trac.nginx.org/nginx/ticket/425),
925 // don't terminate the connection if the stapled response is expired.
926 // We will fall back to fetching revocation information.
927 PRErrorCode ocspErrorCode = PR_GetError();
928 if (ocspErrorCode != SEC_ERROR_OCSP_OLD_RESPONSE) {
929 // stapled OCSP response present but invalid for some reason
930 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 4);
931 return rv;
932 } else {
933 // stapled OCSP response present but expired
934 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 3);
935 }
936 } else {
937 // stapled OCSP response present and good
938 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 1);
939 }
940 } else {
941 // no stapled OCSP response
942 Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 2);
944 uint32_t reasonsForNotFetching = 0;
946 char* ocspURI = CERT_GetOCSPAuthorityInfoAccessLocation(cert);
947 if (!ocspURI) {
948 reasonsForNotFetching |= 1; // invalid/missing OCSP URI
949 } else {
950 if (std::strncmp(ocspURI, "http://", 7)) { // approximation
951 reasonsForNotFetching |= 1; // invalid/missing OCSP URI
952 }
953 PORT_Free(ocspURI);
954 }
956 if (!certVerifier.mOCSPDownloadEnabled) {
957 reasonsForNotFetching |= 2;
958 }
960 Telemetry::Accumulate(Telemetry::SSL_OCSP_MAY_FETCH,
961 reasonsForNotFetching);
962 }
963 }
965 // We want to avoid storing any intermediate cert information when browsing
966 // in private, transient contexts.
967 bool saveIntermediates =
968 !(providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE);
970 mozilla::pkix::ScopedCERTCertList certList;
971 SECOidTag evOidPolicy;
972 rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
973 time, infoObject,
974 infoObject->GetHostNameRaw(),
975 saveIntermediates, nullptr,
976 &evOidPolicy);
978 // We want to remember the CA certs in the temp db, so that the application can find the
979 // complete chain at any time it might need it.
980 // But we keep only those CA certs in the temp db, that we didn't already know.
982 RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
983 RefPtr<nsNSSCertificate> nsc;
985 if (!status || !status->mServerCert) {
986 if( rv == SECSuccess ){
987 nsc = nsNSSCertificate::Create(cert, &evOidPolicy);
988 }
989 else {
990 nsc = nsNSSCertificate::Create(cert);
991 }
992 }
994 if (rv == SECSuccess) {
995 // The connection may get terminated, for example, if the server requires
996 // a client cert. Let's provide a minimal SSLStatus
997 // to the caller that contains at least the cert and its status.
998 if (!status) {
999 status = new nsSSLStatus();
1000 infoObject->SetSSLStatus(status);
1001 }
1003 if (rv == SECSuccess) {
1004 // Certificate verification succeeded delete any potential record
1005 // of certificate error bits.
1006 RememberCertErrorsTable::GetInstance().RememberCertHasError(infoObject,
1007 nullptr, rv);
1008 }
1009 else {
1010 // Certificate verification failed, update the status' bits.
1011 RememberCertErrorsTable::GetInstance().LookupCertErrorBits(
1012 infoObject, status);
1013 }
1015 if (status && !status->mServerCert) {
1016 status->mServerCert = nsc;
1017 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1018 ("AuthCertificate setting NEW cert %p\n", status->mServerCert.get()));
1019 }
1020 }
1022 return rv;
1023 }
1025 /*static*/ SECStatus
1026 SSLServerCertVerificationJob::Dispatch(
1027 const RefPtr<SharedCertVerifier>& certVerifier,
1028 const void* fdForLogging,
1029 TransportSecurityInfo* infoObject,
1030 CERTCertificate* serverCert,
1031 SECItem* stapledOCSPResponse,
1032 uint32_t providerFlags,
1033 PRTime time)
1034 {
1035 // Runs on the socket transport thread
1036 if (!certVerifier || !infoObject || !serverCert) {
1037 NS_ERROR("Invalid parameters for SSL server cert validation");
1038 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1039 return SECFailure;
1040 }
1042 RefPtr<SSLServerCertVerificationJob> job(
1043 new SSLServerCertVerificationJob(certVerifier, fdForLogging, infoObject,
1044 serverCert, stapledOCSPResponse,
1045 providerFlags, time));
1047 nsresult nrv;
1048 if (!gCertVerificationThreadPool) {
1049 nrv = NS_ERROR_NOT_INITIALIZED;
1050 } else {
1051 nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL);
1052 }
1053 if (NS_FAILED(nrv)) {
1054 // We can't call SetCertVerificationResult here to change
1055 // mCertVerificationState because SetCertVerificationResult will call
1056 // libssl functions that acquire SSL locks that are already being held at
1057 // this point. infoObject->mCertVerificationState will be stuck at
1058 // waiting_for_cert_verification here, but that is OK because we already
1059 // have to be able to handle cases where we encounter non-cert errors while
1060 // in that state.
1061 PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY
1062 ? SEC_ERROR_NO_MEMORY
1063 : PR_INVALID_STATE_ERROR;
1064 PORT_SetError(error);
1065 return SECFailure;
1066 }
1068 PORT_SetError(PR_WOULD_BLOCK_ERROR);
1069 return SECWouldBlock;
1070 }
1072 NS_IMETHODIMP
1073 SSLServerCertVerificationJob::Run()
1074 {
1075 // Runs on a cert verification thread
1077 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1078 ("[%p] SSLServerCertVerificationJob::Run\n", mInfoObject.get()));
1080 PRErrorCode error;
1082 nsNSSShutDownPreventionLock nssShutdownPrevention;
1083 if (mInfoObject->isAlreadyShutDown()) {
1084 error = SEC_ERROR_USER_CANCELLED;
1085 } else {
1086 Telemetry::ID successTelemetry;
1087 Telemetry::ID failureTelemetry;
1088 switch (mCertVerifier->mImplementation) {
1089 case CertVerifier::classic:
1090 successTelemetry
1091 = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_CLASSIC;
1092 failureTelemetry
1093 = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_CLASSIC;
1094 break;
1095 case CertVerifier::mozillapkix:
1096 successTelemetry
1097 = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX;
1098 failureTelemetry
1099 = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX;
1100 break;
1101 #ifndef NSS_NO_LIBPKIX
1102 case CertVerifier::libpkix:
1103 successTelemetry
1104 = Telemetry::SSL_SUCCESFUL_CERT_VALIDATION_TIME_LIBPKIX;
1105 failureTelemetry
1106 = Telemetry::SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_LIBPKIX;
1107 break;
1108 #endif
1109 default:
1110 MOZ_CRASH("Unknown CertVerifier mode");
1111 }
1113 // XXX
1114 // Reset the error code here so we can detect if AuthCertificate fails to
1115 // set the error code if/when it fails.
1116 PR_SetError(0, 0);
1117 SECStatus rv = AuthCertificate(*mCertVerifier, mInfoObject, mCert.get(),
1118 mStapledOCSPResponse, mProviderFlags,
1119 mTime);
1120 if (rv == SECSuccess) {
1121 uint32_t interval = (uint32_t) ((TimeStamp::Now() - mJobStartTime).ToMilliseconds());
1122 RefPtr<SSLServerCertVerificationResult> restart(
1123 new SSLServerCertVerificationResult(mInfoObject, 0,
1124 successTelemetry, interval));
1125 restart->Dispatch();
1126 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
1127 return NS_OK;
1128 }
1130 // Note: the interval is not calculated once as PR_GetError MUST be called
1131 // before any other function call
1132 error = PR_GetError();
1133 {
1134 TimeStamp now = TimeStamp::Now();
1135 MutexAutoLock telemetryMutex(*gSSLVerificationTelemetryMutex);
1136 Telemetry::AccumulateTimeDelta(failureTelemetry, mJobStartTime, now);
1137 }
1138 if (error != 0) {
1139 RefPtr<CertErrorRunnable> runnable(
1140 CreateCertErrorRunnable(*mCertVerifier, error, mInfoObject,
1141 mCert.get(), mStapledOCSPResponse,
1142 mFdForLogging, mProviderFlags, mTime));
1143 if (!runnable) {
1144 // CreateCertErrorRunnable set a new error code
1145 error = PR_GetError();
1146 } else {
1147 // We must block the the socket transport service thread while the
1148 // main thread executes the CertErrorRunnable. The CertErrorRunnable
1149 // will dispatch the result asynchronously, so we don't have to block
1150 // this thread waiting for it.
1152 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1153 ("[%p][%p] Before dispatching CertErrorRunnable\n",
1154 mFdForLogging, runnable.get()));
1156 nsresult nrv;
1157 nsCOMPtr<nsIEventTarget> stsTarget
1158 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
1159 if (NS_SUCCEEDED(nrv)) {
1160 nrv = stsTarget->Dispatch(new CertErrorRunnableRunnable(runnable),
1161 NS_DISPATCH_NORMAL);
1162 }
1163 if (NS_SUCCEEDED(nrv)) {
1164 return NS_OK;
1165 }
1167 NS_ERROR("Failed to dispatch CertErrorRunnable");
1168 error = PR_INVALID_STATE_ERROR;
1169 }
1170 }
1171 }
1173 if (error == 0) {
1174 NS_NOTREACHED("no error set during certificate validation failure");
1175 error = PR_INVALID_STATE_ERROR;
1176 }
1178 RefPtr<SSLServerCertVerificationResult> failure(
1179 new SSLServerCertVerificationResult(mInfoObject, error));
1180 failure->Dispatch();
1181 return NS_OK;
1182 }
1184 } // unnamed namespace
1186 // Extracts whatever information we need out of fd (using SSL_*) and passes it
1187 // to SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob should
1188 // never do anything with fd except logging.
1189 SECStatus
1190 AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer)
1191 {
1192 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
1193 if (!certVerifier) {
1194 PR_SetError(SEC_ERROR_NOT_INITIALIZED, 0);
1195 return SECFailure;
1196 }
1198 // Runs on the socket transport thread
1200 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1201 ("[%p] starting AuthCertificateHook\n", fd));
1203 // Modern libssl always passes PR_TRUE for checkSig, and we have no means of
1204 // doing verification without checking signatures.
1205 NS_ASSERTION(checkSig, "AuthCertificateHook: checkSig unexpectedly false");
1207 // PSM never causes libssl to call this function with PR_TRUE for isServer,
1208 // and many things in PSM assume that we are a client.
1209 NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");
1211 nsNSSSocketInfo* socketInfo = static_cast<nsNSSSocketInfo*>(arg);
1213 ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
1215 if (!checkSig || isServer || !socketInfo || !serverCert) {
1216 PR_SetError(PR_INVALID_STATE_ERROR, 0);
1217 return SECFailure;
1218 }
1220 socketInfo->SetFullHandshake();
1222 // This value of "now" is used both here for OCSP stapling and later
1223 // when calling CreateCertErrorRunnable.
1224 PRTime now = PR_Now();
1226 if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess)
1227 return SECFailure;
1229 bool onSTSThread;
1230 nsresult nrv;
1231 nsCOMPtr<nsIEventTarget> sts
1232 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
1233 if (NS_SUCCEEDED(nrv)) {
1234 nrv = sts->IsOnCurrentThread(&onSTSThread);
1235 }
1237 if (NS_FAILED(nrv)) {
1238 NS_ERROR("Could not get STS service or IsOnCurrentThread failed");
1239 PR_SetError(PR_UNKNOWN_ERROR, 0);
1240 return SECFailure;
1241 }
1243 // SSL_PeerStapledOCSPResponses will never return a non-empty response if
1244 // OCSP stapling wasn't enabled because libssl wouldn't have let the server
1245 // return a stapled OCSP response.
1246 // We don't own these pointers.
1247 const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd);
1248 SECItem* stapledOCSPResponse = nullptr;
1249 // we currently only support single stapled responses
1250 if (csa && csa->len == 1) {
1251 stapledOCSPResponse = &csa->items[0];
1252 }
1254 uint32_t providerFlags = 0;
1255 socketInfo->GetProviderFlags(&providerFlags);
1257 if (onSTSThread) {
1259 // We *must* do certificate verification on a background thread because
1260 // we need the socket transport thread to be free for our OCSP requests,
1261 // and we *want* to do certificate verification on a background thread
1262 // because of the performance benefits of doing so.
1263 socketInfo->SetCertVerificationWaiting();
1264 SECStatus rv = SSLServerCertVerificationJob::Dispatch(
1265 certVerifier, static_cast<const void*>(fd), socketInfo,
1266 serverCert, stapledOCSPResponse, providerFlags, now);
1267 return rv;
1268 }
1270 // We can't do certificate verification on a background thread, because the
1271 // thread doing the network I/O may not interrupt its network I/O on receipt
1272 // of our SSLServerCertVerificationResult event, and/or it might not even be
1273 // a non-blocking socket.
1275 SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert,
1276 stapledOCSPResponse, providerFlags, now);
1277 if (rv == SECSuccess) {
1278 Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1);
1279 return SECSuccess;
1280 }
1282 PRErrorCode error = PR_GetError();
1283 if (error != 0) {
1284 RefPtr<CertErrorRunnable> runnable(
1285 CreateCertErrorRunnable(*certVerifier, error, socketInfo, serverCert,
1286 stapledOCSPResponse,
1287 static_cast<const void*>(fd), providerFlags,
1288 now));
1289 if (!runnable) {
1290 // CreateCertErrorRunnable sets a new error code when it fails
1291 error = PR_GetError();
1292 } else {
1293 // We have to return SECSuccess or SECFailure based on the result of the
1294 // override processing, so we must block this thread waiting for it. The
1295 // CertErrorRunnable will NOT dispatch the result at all, since we passed
1296 // false for CreateCertErrorRunnable's async parameter
1297 nrv = runnable->DispatchToMainThreadAndWait();
1298 if (NS_FAILED(nrv)) {
1299 NS_ERROR("Failed to dispatch CertErrorRunnable");
1300 PR_SetError(PR_INVALID_STATE_ERROR, 0);
1301 return SECFailure;
1302 }
1304 if (!runnable->mResult) {
1305 NS_ERROR("CertErrorRunnable did not set result");
1306 PR_SetError(PR_INVALID_STATE_ERROR, 0);
1307 return SECFailure;
1308 }
1310 if (runnable->mResult->mErrorCode == 0) {
1311 return SECSuccess; // cert error override occurred.
1312 }
1314 // We must call SetCanceled here to set the error message type
1315 // in case it isn't PlainErrorMessage, which is what we would
1316 // default to if we just called
1317 // PR_SetError(runnable->mResult->mErrorCode, 0) and returned
1318 // SECFailure without doing this.
1319 socketInfo->SetCanceled(runnable->mResult->mErrorCode,
1320 runnable->mResult->mErrorMessageType);
1321 error = runnable->mResult->mErrorCode;
1322 }
1323 }
1325 if (error == 0) {
1326 NS_ERROR("error code not set");
1327 error = PR_UNKNOWN_ERROR;
1328 }
1330 PR_SetError(error, 0);
1331 return SECFailure;
1332 }
1334 #ifndef MOZ_NO_EV_CERTS
1335 class InitializeIdentityInfo : public CryptoTask
1336 {
1337 virtual nsresult CalculateResult() MOZ_OVERRIDE
1338 {
1339 EnsureIdentityInfoLoaded();
1340 return NS_OK;
1341 }
1343 virtual void ReleaseNSSResources() MOZ_OVERRIDE { } // no-op
1344 virtual void CallCallback(nsresult rv) MOZ_OVERRIDE { } // no-op
1345 };
1346 #endif
1348 void EnsureServerVerificationInitialized()
1349 {
1350 #ifndef MOZ_NO_EV_CERTS
1351 // Should only be called from socket transport thread due to the static
1352 // variable and the reference to gCertVerificationThreadPool
1354 static bool triggeredCertVerifierInit = false;
1355 if (triggeredCertVerifierInit)
1356 return;
1357 triggeredCertVerifierInit = true;
1359 RefPtr<InitializeIdentityInfo> initJob = new InitializeIdentityInfo();
1360 if (gCertVerificationThreadPool)
1361 gCertVerificationThreadPool->Dispatch(initJob, NS_DISPATCH_NORMAL);
1362 #endif
1363 }
1365 SSLServerCertVerificationResult::SSLServerCertVerificationResult(
1366 TransportSecurityInfo* infoObject, PRErrorCode errorCode,
1367 Telemetry::ID telemetryID, uint32_t telemetryValue,
1368 SSLErrorMessageType errorMessageType)
1369 : mInfoObject(infoObject)
1370 , mErrorCode(errorCode)
1371 , mErrorMessageType(errorMessageType)
1372 , mTelemetryID(telemetryID)
1373 , mTelemetryValue(telemetryValue)
1374 {
1375 // We accumulate telemetry for (only) successful validations on the main thread
1376 // to avoid adversely affecting performance by acquiring the mutex that we use
1377 // when accumulating the telemetry for unsuccessful validations. Unsuccessful
1378 // validations times are accumulated elsewhere.
1379 MOZ_ASSERT(telemetryID == Telemetry::HistogramCount || errorCode == 0);
1380 }
1382 void
1383 SSLServerCertVerificationResult::Dispatch()
1384 {
1385 nsresult rv;
1386 nsCOMPtr<nsIEventTarget> stsTarget
1387 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
1388 NS_ASSERTION(stsTarget,
1389 "Failed to get socket transport service event target");
1390 rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL);
1391 NS_ASSERTION(NS_SUCCEEDED(rv),
1392 "Failed to dispatch SSLServerCertVerificationResult");
1393 }
1395 NS_IMETHODIMP
1396 SSLServerCertVerificationResult::Run()
1397 {
1398 // TODO: Assert that we're on the socket transport thread
1399 if (mTelemetryID != Telemetry::HistogramCount) {
1400 Telemetry::Accumulate(mTelemetryID, mTelemetryValue);
1401 }
1402 // XXX: This cast will be removed by the next patch
1403 ((nsNSSSocketInfo*) mInfoObject.get())
1404 ->SetCertVerificationResult(mErrorCode, mErrorMessageType);
1405 return NS_OK;
1406 }
1408 } } // namespace mozilla::psm