bug 700693 - OCSP stapling PSM changes r=bsmith
[gecko.git] / security / manager / ssl / src / nsNSSIOLayer.cpp
blob5662858047e7155e81e7a3111ad34fe7be301e0e
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/. */
7 #include "nsNSSComponent.h"
8 #include "nsNSSIOLayer.h"
10 #include "mozilla/Telemetry.h"
12 #include "prlog.h"
13 #include "prnetdb.h"
14 #include "nsIPrefService.h"
15 #include "nsIClientAuthDialogs.h"
16 #include "nsClientAuthRemember.h"
17 #include "nsISSLErrorListener.h"
19 #include "nsNetUtil.h"
20 #include "nsPrintfCString.h"
21 #include "SSLServerCertVerification.h"
22 #include "nsNSSCertHelper.h"
23 #include "nsNSSCleaner.h"
25 #ifndef NSS_NO_LIBPKIX
26 #include "nsIDocShell.h"
27 #include "nsIDocShellTreeItem.h"
28 #include "nsISecureBrowserUI.h"
29 #include "nsIInterfaceRequestorUtils.h"
30 #endif
32 #include "nsCharSeparatedTokenizer.h"
33 #include "nsIConsoleService.h"
34 #include "PSMRunnable.h"
35 #include "ScopedNSSTypes.h"
36 #include "SharedSSLState.h"
37 #include "mozilla/Preferences.h"
39 #include "ssl.h"
40 #include "secerr.h"
41 #include "sslerr.h"
42 #include "secder.h"
43 #include "keyhi.h"
45 using namespace mozilla;
46 using namespace mozilla::psm;
48 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
49 //reports when doing SSL read/write
51 //#define DUMP_BUFFER //Enable this define along with
52 //DEBUG_SSL_VERBOSE to dump SSL
53 //read/write buffer to a log.
54 //Uses PR_LOG except on Mac where
55 //we always write out to our own
56 //file.
58 namespace {
60 NSSCleanupAutoPtrClass(void, PR_FREEIF)
62 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
64 /* SSM_UserCertChoice: enum for cert choice info */
65 typedef enum {ASK, AUTO} SSM_UserCertChoice;
67 } // unnamed namespace
69 #ifdef PR_LOGGING
70 extern PRLogModuleInfo* gPIPNSSLog;
71 #endif
73 nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
74 : mFd(nullptr),
75 mCertVerificationState(before_cert_verification),
76 mSharedState(aState),
77 mForSTARTTLS(false),
78 mSSL3Enabled(false),
79 mTLSEnabled(false),
80 mHandshakePending(true),
81 mHasCleartextPhase(false),
82 mHandshakeInProgress(false),
83 mAllowTLSIntoleranceTimeout(true),
84 mRememberClientAuthCertificate(false),
85 mHandshakeStartTime(0),
86 mFirstServerHelloReceived(false),
87 mNPNCompleted(false),
88 mHandshakeCompleted(false),
89 mJoined(false),
90 mSentClientCert(false),
91 mProviderFlags(providerFlags),
92 mSocketCreationTimestamp(TimeStamp::Now()),
93 mPlaintextBytesRead(0)
97 NS_IMPL_ISUPPORTS_INHERITED2(nsNSSSocketInfo, TransportSecurityInfo,
98 nsISSLSocketControl,
99 nsIClientAuthUserDecision)
101 NS_IMETHODIMP
102 nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags)
104 *aProviderFlags = mProviderFlags;
105 return NS_OK;
108 nsresult
109 nsNSSSocketInfo::GetHandshakePending(bool *aHandshakePending)
111 *aHandshakePending = mHandshakePending;
112 return NS_OK;
115 nsresult
116 nsNSSSocketInfo::SetHandshakePending(bool aHandshakePending)
118 mHandshakePending = aHandshakePending;
119 return NS_OK;
122 NS_IMETHODIMP nsNSSSocketInfo::GetRememberClientAuthCertificate(bool *aRememberClientAuthCertificate)
124 NS_ENSURE_ARG_POINTER(aRememberClientAuthCertificate);
125 *aRememberClientAuthCertificate = mRememberClientAuthCertificate;
126 return NS_OK;
129 NS_IMETHODIMP nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRememberClientAuthCertificate)
131 mRememberClientAuthCertificate = aRememberClientAuthCertificate;
132 return NS_OK;
135 void nsNSSSocketInfo::SetHasCleartextPhase(bool aHasCleartextPhase)
137 mHasCleartextPhase = aHasCleartextPhase;
140 bool nsNSSSocketInfo::GetHasCleartextPhase()
142 return mHasCleartextPhase;
145 NS_IMETHODIMP
146 nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
148 *aCallbacks = mCallbacks;
149 NS_IF_ADDREF(*aCallbacks);
150 return NS_OK;
153 NS_IMETHODIMP
154 nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
156 if (!aCallbacks) {
157 mCallbacks = nullptr;
158 return NS_OK;
161 mCallbacks = aCallbacks;
163 return NS_OK;
166 #ifndef NSS_NO_LIBPKIX
167 static void
168 getSecureBrowserUI(nsIInterfaceRequestor * callbacks,
169 nsISecureBrowserUI ** result)
171 NS_ASSERTION(result, "result parameter to getSecureBrowserUI is null");
172 *result = nullptr;
174 NS_ASSERTION(NS_IsMainThread(),
175 "getSecureBrowserUI called off the main thread");
177 if (!callbacks)
178 return;
180 nsCOMPtr<nsISecureBrowserUI> secureUI = do_GetInterface(callbacks);
181 if (secureUI) {
182 secureUI.forget(result);
183 return;
186 nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(callbacks);
187 if (item) {
188 nsCOMPtr<nsIDocShellTreeItem> rootItem;
189 (void) item->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
191 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(rootItem);
192 if (docShell) {
193 (void) docShell->GetSecurityUI(result);
197 #endif
199 void
200 nsNSSSocketInfo::SetHandshakeCompleted(bool aResumedSession)
202 if (!mHandshakeCompleted) {
203 // This will include TCP and proxy tunnel wait time
204 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
205 mSocketCreationTimestamp, TimeStamp::Now());
207 // If the handshake is completed for the first time from just 1 callback
208 // that means that TLS session resumption must have been used.
209 Telemetry::Accumulate(Telemetry::SSL_RESUMED_SESSION, aResumedSession);
211 // Remove the plain text layer as it is not needed anymore.
212 // The plain text layer is not always present - so its not a fatal error
213 // if it cannot be removed
214 PRFileDesc* poppedPlaintext =
215 PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
216 if (poppedPlaintext) {
217 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
218 poppedPlaintext->dtor(poppedPlaintext);
221 mHandshakeCompleted = true;
225 void
226 nsNSSSocketInfo::SetNegotiatedNPN(const char *value, uint32_t length)
228 if (!value)
229 mNegotiatedNPN.Truncate();
230 else
231 mNegotiatedNPN.Assign(value, length);
232 mNPNCompleted = true;
235 NS_IMETHODIMP
236 nsNSSSocketInfo::GetNegotiatedNPN(nsACString &aNegotiatedNPN)
238 if (!mNPNCompleted)
239 return NS_ERROR_NOT_CONNECTED;
241 aNegotiatedNPN = mNegotiatedNPN;
242 return NS_OK;
245 NS_IMETHODIMP
246 nsNSSSocketInfo::JoinConnection(const nsACString & npnProtocol,
247 const nsACString & hostname,
248 int32_t port,
249 bool *_retval)
251 *_retval = false;
253 // Different ports may not be joined together
254 if (port != GetPort())
255 return NS_OK;
257 // Make sure NPN has been completed and matches requested npnProtocol
258 if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
259 return NS_OK;
261 // If this is the same hostname then the certicate status does not
262 // need to be considered. They are joinable.
263 if (GetHostName() && hostname.Equals(GetHostName())) {
264 *_retval = true;
265 return NS_OK;
268 // Before checking the server certificate we need to make sure the
269 // handshake has completed.
270 if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
271 return NS_OK;
273 // If the cert has error bits (e.g. it is untrusted) then do not join.
274 // The value of mHaveCertErrorBits is only reliable because we know that
275 // the handshake completed.
276 if (SSLStatus()->mHaveCertErrorBits)
277 return NS_OK;
279 // If the connection is using client certificates then do not join
280 // because the user decides on whether to send client certs to hosts on a
281 // per-domain basis.
282 if (mSentClientCert)
283 return NS_OK;
285 // Ensure that the server certificate covers the hostname that would
286 // like to join this connection
288 ScopedCERTCertificate nssCert;
290 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
291 if (cert2)
292 nssCert = cert2->GetCert();
294 if (!nssCert)
295 return NS_OK;
297 if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
298 SECSuccess)
299 return NS_OK;
301 // All tests pass - this is joinable
302 mJoined = true;
303 *_retval = true;
304 return NS_OK;
307 nsresult
308 nsNSSSocketInfo::GetForSTARTTLS(bool* aForSTARTTLS)
310 *aForSTARTTLS = mForSTARTTLS;
311 return NS_OK;
314 nsresult
315 nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
317 mForSTARTTLS = aForSTARTTLS;
318 return NS_OK;
321 NS_IMETHODIMP
322 nsNSSSocketInfo::ProxyStartSSL()
324 return ActivateSSL();
327 NS_IMETHODIMP
328 nsNSSSocketInfo::StartTLS()
330 return ActivateSSL();
333 NS_IMETHODIMP
334 nsNSSSocketInfo::SetNPNList(nsTArray<nsCString> &protocolArray)
336 nsNSSShutDownPreventionLock locker;
337 if (isAlreadyShutDown())
338 return NS_ERROR_NOT_AVAILABLE;
339 if (!mFd)
340 return NS_ERROR_FAILURE;
342 // the npn list is a concatenated list of 8 bit byte strings.
343 nsCString npnList;
345 for (uint32_t index = 0; index < protocolArray.Length(); ++index) {
346 if (protocolArray[index].IsEmpty() ||
347 protocolArray[index].Length() > 255)
348 return NS_ERROR_ILLEGAL_VALUE;
350 npnList.Append(protocolArray[index].Length());
351 npnList.Append(protocolArray[index]);
354 if (SSL_SetNextProtoNego(
355 mFd,
356 reinterpret_cast<const unsigned char *>(npnList.get()),
357 npnList.Length()) != SECSuccess)
358 return NS_ERROR_FAILURE;
360 return NS_OK;
363 nsresult nsNSSSocketInfo::ActivateSSL()
365 nsNSSShutDownPreventionLock locker;
366 if (isAlreadyShutDown())
367 return NS_ERROR_NOT_AVAILABLE;
369 if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
370 return NS_ERROR_FAILURE;
371 if (SECSuccess != SSL_ResetHandshake(mFd, false))
372 return NS_ERROR_FAILURE;
374 mHandshakePending = true;
376 return NS_OK;
379 nsresult nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
381 *aFilePtr = mFd;
382 return NS_OK;
385 nsresult nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
387 mFd = aFilePtr;
388 return NS_OK;
391 #ifndef NSS_NO_LIBPKIX
392 class PreviousCertRunnable : public SyncRunnableBase
394 public:
395 PreviousCertRunnable(nsIInterfaceRequestor * callbacks)
396 : mCallbacks(callbacks)
400 virtual void RunOnTargetThread()
402 nsCOMPtr<nsISecureBrowserUI> secureUI;
403 getSecureBrowserUI(mCallbacks, getter_AddRefs(secureUI));
404 nsCOMPtr<nsISSLStatusProvider> statusProvider = do_QueryInterface(secureUI);
405 if (statusProvider) {
406 nsCOMPtr<nsISSLStatus> status;
407 (void) statusProvider->GetSSLStatus(getter_AddRefs(status));
408 if (status) {
409 (void) status->GetServerCert(getter_AddRefs(mPreviousCert));
414 nsCOMPtr<nsIX509Cert> mPreviousCert; // out
415 private:
416 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; // in
418 #endif
420 void nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
422 NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
423 *_result = nullptr;
425 #ifndef NSS_NO_LIBPKIX
426 RefPtr<PreviousCertRunnable> runnable(new PreviousCertRunnable(mCallbacks));
427 nsresult rv = runnable->DispatchToMainThreadAndWait();
428 NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
429 runnable->mPreviousCert.forget(_result);
430 #endif
433 void
434 nsNSSSocketInfo::SetCertVerificationWaiting()
436 // mCertVerificationState may be before_cert_verification for the first
437 // handshake on the connection, or after_cert_verification for subsequent
438 // renegotiation handshakes.
439 NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
440 "Invalid state transition to waiting_for_cert_verification");
441 mCertVerificationState = waiting_for_cert_verification;
444 // Be careful that SetCertVerificationResult does NOT get called while we are
445 // processing a SSL callback function, because SSL_AuthCertificateComplete will
446 // attempt to acquire locks that are already held by libssl when it calls
447 // callbacks.
448 void
449 nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
450 SSLErrorMessageType errorMessageType)
452 NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
453 "Invalid state transition to cert_verification_finished");
455 if (mFd) {
456 SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
457 // Only replace errorCode if there was originally no error
458 if (rv != SECSuccess && errorCode == 0) {
459 errorCode = PR_GetError();
460 errorMessageType = PlainErrorMessage;
461 if (errorCode == 0) {
462 NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
463 errorCode = PR_INVALID_STATE_ERROR;
468 if (errorCode) {
469 SetCanceled(errorCode, errorMessageType);
472 if (mPlaintextBytesRead && !errorCode) {
473 Telemetry::Accumulate(Telemetry::SSL_BYTES_BEFORE_CERT_CALLBACK, mPlaintextBytesRead);
476 mCertVerificationState = after_cert_verification;
479 void nsNSSSocketInfo::SetHandshakeInProgress(bool aIsIn)
481 mHandshakeInProgress = aIsIn;
483 if (mHandshakeInProgress && !mHandshakeStartTime)
485 mHandshakeStartTime = PR_IntervalNow();
489 void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(bool aAllow)
491 mAllowTLSIntoleranceTimeout = aAllow;
494 SharedSSLState& nsNSSSocketInfo::SharedState()
496 return mSharedState;
499 bool nsNSSSocketInfo::HandshakeTimeout()
501 if (!mAllowTLSIntoleranceTimeout)
502 return false;
504 if (!mHandshakeInProgress)
505 return false; // have not even sent client hello yet
507 if (mFirstServerHelloReceived)
508 return false;
510 // Now we know we are in the first handshake, and haven't received the
511 // ServerHello+Certificate sequence or the
512 // ServerHello+ChangeCipherSpec+Finished sequence.
514 // XXX: Bug 754356 - waiting to receive the Certificate or Finished messages
515 // may cause us to time out in cases where we shouldn't.
517 static const PRIntervalTime handshakeTimeoutInterval
518 = PR_SecondsToInterval(25);
520 PRIntervalTime now = PR_IntervalNow();
521 bool result = (now - mHandshakeStartTime) > handshakeTimeoutInterval;
522 return result;
525 void nsSSLIOLayerHelpers::Cleanup()
527 if (mTLSIntolerantSites) {
528 delete mTLSIntolerantSites;
529 mTLSIntolerantSites = nullptr;
532 if (mTLSTolerantSites) {
533 delete mTLSTolerantSites;
534 mTLSTolerantSites = nullptr;
537 if (mRenegoUnrestrictedSites) {
538 delete mRenegoUnrestrictedSites;
539 mRenegoUnrestrictedSites = nullptr;
542 if (mutex) {
543 delete mutex;
544 mutex = nullptr;
548 static void
549 nsHandleSSLError(nsNSSSocketInfo *socketInfo,
550 ::mozilla::psm::SSLErrorMessageType errtype,
551 PRErrorCode err)
553 if (!NS_IsMainThread()) {
554 NS_ERROR("nsHandleSSLError called off the main thread");
555 return;
558 // SetCanceled is only called by the main thread or the socket transport
559 // thread. Whenever this function is called on the main thread, the SSL
560 // thread is blocked on it. So, no mutex is necessary for
561 // SetCanceled()/GetError*().
562 if (socketInfo->GetErrorCode()) {
563 // If the socket has been flagged as canceled,
564 // the code who did was responsible for setting the error code.
565 return;
568 nsresult rv;
569 NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
570 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
571 if (NS_FAILED(rv))
572 return;
574 nsXPIDLCString hostName;
575 socketInfo->GetHostName(getter_Copies(hostName));
577 int32_t port;
578 socketInfo->GetPort(&port);
580 // Try to get a nsISSLErrorListener implementation from the socket consumer.
581 nsCOMPtr<nsIInterfaceRequestor> cb;
582 socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
583 if (cb) {
584 nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(cb);
585 if (sel) {
586 nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(socketInfo);
587 nsCString hostWithPortString = hostName;
588 hostWithPortString.AppendLiteral(":");
589 hostWithPortString.AppendInt(port);
591 bool suppressMessage = false; // obsolete, ignored
592 rv = sel->NotifySSLError(csi, err, hostWithPortString, &suppressMessage);
596 // We must cancel first, which sets the error code.
597 socketInfo->SetCanceled(err, PlainErrorMessage);
598 nsXPIDLString errorString;
599 socketInfo->GetErrorLogMessage(err, errtype, errorString);
601 if (!errorString.IsEmpty()) {
602 nsCOMPtr<nsIConsoleService> console;
603 console = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
604 if (console) {
605 console->LogStringMessage(errorString.get());
610 namespace {
612 enum Operation { reading, writing, not_reading_or_writing };
614 int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
615 PRFileDesc* ssl_layer_fd,
616 nsNSSSocketInfo *socketInfo);
618 nsNSSSocketInfo *
619 getSocketInfoIfRunning(PRFileDesc * fd, Operation op,
620 const nsNSSShutDownPreventionLock & /*proofOfLock*/)
622 if (!fd || !fd->lower || !fd->secret ||
623 fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
624 NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
625 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
626 return nullptr;
629 nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
631 if (socketInfo->isAlreadyShutDown() || socketInfo->isPK11LoggedOut()) {
632 PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
633 return nullptr;
636 if (socketInfo->GetErrorCode()) {
637 PRErrorCode err = socketInfo->GetErrorCode();
638 PR_SetError(err, 0);
639 if (op == reading || op == writing) {
640 // We must do TLS intolerance checks for reads and writes, for timeouts
641 // in particular.
642 (void) checkHandshake(-1, op == reading, fd, socketInfo);
645 // If we get here, it is probably because cert verification failed and this
646 // is the first I/O attempt since that failure.
647 return nullptr;
650 return socketInfo;
653 } // unnnamed namespace
655 static PRStatus
656 nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
657 PRIntervalTime timeout)
659 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n", (void*)fd));
660 nsNSSShutDownPreventionLock locker;
661 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
662 return PR_FAILURE;
664 PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
665 if (status != PR_SUCCESS) {
666 PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
667 (void*)fd, PR_GetError()));
668 return status;
671 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*)fd));
672 return status;
675 void
676 nsSSLIOLayerHelpers::getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key)
678 int32_t port;
679 socketInfo->GetPort(&port);
681 nsXPIDLCString host;
682 socketInfo->GetHostName(getter_Copies(host));
684 key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
687 // Call this function to report a site that is possibly TLS intolerant.
688 // This function will return true, if the given socket is currently using TLS,
689 // and it's allowed to retry. Retrying only makes sense if an older
690 // protocol is enabled.
691 bool
692 nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo)
694 nsAutoCString key;
695 getSiteKey(socketInfo, key);
697 if (!socketInfo->IsTLSEnabled()) {
698 // We did not offer TLS but failed with an intolerant error using
699 // a different protocol. To give TLS a try on next connection attempt again
700 // drop this site from the list of intolerant sites. TLS failure might be
701 // caused only by a traffic congestion while the server is TLS tolerant.
702 removeIntolerantSite(key);
703 return false;
706 if (socketInfo->IsSSL3Enabled()) {
707 // Add this site to the list of TLS intolerant sites.
708 addIntolerantSite(key);
710 else {
711 return false; // doesn't make sense to retry
714 return socketInfo->IsTLSEnabled();
717 void
718 nsSSLIOLayerHelpers::rememberTolerantSite(nsNSSSocketInfo *socketInfo)
720 if (!socketInfo->IsTLSEnabled())
721 return;
723 nsAutoCString key;
724 getSiteKey(socketInfo, key);
726 MutexAutoLock lock(*mutex);
727 nsSSLIOLayerHelpers::mTLSTolerantSites->PutEntry(key);
730 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
731 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
732 PRDescIdentity nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity;
733 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
734 PRIOMethods nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods;
736 static PRStatus
737 nsSSLIOLayerClose(PRFileDesc *fd)
739 nsNSSShutDownPreventionLock locker;
740 if (!fd)
741 return PR_FAILURE;
743 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
745 nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
746 NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
748 return socketInfo->CloseSocketAndDestroy(locker);
751 PRStatus nsNSSSocketInfo::CloseSocketAndDestroy(
752 const nsNSSShutDownPreventionLock & /*proofOfLock*/)
754 nsNSSShutDownList::trackSSLSocketClose();
756 PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
757 NS_ASSERTION(popped &&
758 popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
759 "SSL Layer not on top of stack");
761 // The plain text layer is not always present - so its not a fatal error
762 // if it cannot be removed
763 PRFileDesc* poppedPlaintext =
764 PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
765 if (poppedPlaintext) {
766 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
767 poppedPlaintext->dtor(poppedPlaintext);
770 PRStatus status = mFd->methods->close(mFd);
772 // the nsNSSSocketInfo instance can out-live the connection, so we need some
773 // indication that the connection has been closed. mFd == nullptr is that
774 // indication. This is needed, for example, when the connection is closed
775 // before we have finished validating the server's certificate.
776 mFd = nullptr;
778 if (status != PR_SUCCESS) return status;
780 popped->identity = PR_INVALID_IO_LAYER;
781 NS_RELEASE_THIS();
782 popped->dtor(popped);
784 return PR_SUCCESS;
787 #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
788 /* Dumps a (potentially binary) buffer using SSM_DEBUG.
789 (We could have used the version in ssltrace.c, but that's
790 specifically tailored to SSLTRACE. Sigh. */
791 #define DUMPBUF_LINESIZE 24
792 static void
793 nsDumpBuffer(unsigned char *buf, int len)
795 char hexbuf[DUMPBUF_LINESIZE*3+1];
796 char chrbuf[DUMPBUF_LINESIZE+1];
797 static const char *hex = "0123456789abcdef";
798 int i = 0, l = 0;
799 char ch, *c, *h;
800 if (len == 0)
801 return;
802 hexbuf[DUMPBUF_LINESIZE*3] = '\0';
803 chrbuf[DUMPBUF_LINESIZE] = '\0';
804 (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
805 (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
806 h = hexbuf;
807 c = chrbuf;
809 while (i < len)
811 ch = buf[i];
813 if (l == DUMPBUF_LINESIZE)
815 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
816 (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
817 (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
818 h = hexbuf;
819 c = chrbuf;
820 l = 0;
823 /* Convert a character to hex. */
824 *h++ = hex[(ch >> 4) & 0xf];
825 *h++ = hex[ch & 0xf];
826 h++;
828 /* Put the character (if it's printable) into the character buffer. */
829 if ((ch >= 0x20) && (ch <= 0x7e))
830 *c++ = ch;
831 else
832 *c++ = '.';
833 i++; l++;
835 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
838 #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
839 #else
840 #define DEBUG_DUMP_BUFFER(buf,len)
841 #endif
843 static bool
844 isNonSSLErrorThatWeAllowToRetry(int32_t err, bool withInitialCleartext)
846 switch (err)
848 case PR_CONNECT_RESET_ERROR:
849 if (!withInitialCleartext)
850 return true;
851 break;
853 case PR_END_OF_FILE_ERROR:
854 return true;
857 return false;
860 static bool
861 isTLSIntoleranceError(int32_t err, bool withInitialCleartext)
863 // This function is supposed to decide, which error codes should
864 // be used to conclude server is TLS intolerant.
865 // Note this only happens during the initial SSL handshake.
867 // When not using a proxy we'll see a connection reset error.
868 // When using a proxy, we'll see an end of file error.
869 // In addition check for some error codes where it is reasonable
870 // to retry without TLS.
872 if (isNonSSLErrorThatWeAllowToRetry(err, withInitialCleartext))
873 return true;
875 switch (err)
877 case SSL_ERROR_BAD_MAC_ALERT:
878 case SSL_ERROR_BAD_MAC_READ:
879 case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
880 case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
881 case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
882 case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
883 case SSL_ERROR_NO_CYPHER_OVERLAP:
884 case SSL_ERROR_BAD_SERVER:
885 case SSL_ERROR_BAD_BLOCK_PADDING:
886 case SSL_ERROR_UNSUPPORTED_VERSION:
887 case SSL_ERROR_PROTOCOL_VERSION_ALERT:
888 case SSL_ERROR_RX_MALFORMED_FINISHED:
889 case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
890 case SSL_ERROR_DECODE_ERROR_ALERT:
891 case SSL_ERROR_RX_UNKNOWN_ALERT:
892 return true;
895 return false;
898 class SSLErrorRunnable : public SyncRunnableBase
900 public:
901 SSLErrorRunnable(nsNSSSocketInfo * infoObject,
902 ::mozilla::psm::SSLErrorMessageType errtype,
903 PRErrorCode errorCode)
904 : mInfoObject(infoObject)
905 , mErrType(errtype)
906 , mErrorCode(errorCode)
910 virtual void RunOnTargetThread()
912 nsHandleSSLError(mInfoObject, mErrType, mErrorCode);
915 RefPtr<nsNSSSocketInfo> mInfoObject;
916 ::mozilla::psm::SSLErrorMessageType mErrType;
917 const PRErrorCode mErrorCode;
920 namespace {
922 int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
923 PRFileDesc* ssl_layer_fd,
924 nsNSSSocketInfo *socketInfo)
926 // This is where we work around all of those SSL servers that don't
927 // conform to the SSL spec and shutdown a connection when we request
928 // SSL v3.1 (aka TLS). The spec says the client says what version
929 // of the protocol we're willing to perform, in our case SSL v3.1
930 // In its response, the server says which version it wants to perform.
931 // Many servers out there only know how to do v3.0. Next, we're supposed
932 // to send back the version of the protocol we requested (ie v3.1). At
933 // this point many servers's implementations are broken and they shut
934 // down the connection when they don't see the version they sent back.
935 // This is supposed to prevent a man in the middle from forcing one
936 // side to dumb down to a lower level of the protocol. Unfortunately,
937 // there are enough broken servers out there that such a gross work-around
938 // is necessary. :(
940 // Additional comment added in August 2006:
941 // When we begun to use TLS hello extensions, we encountered a new class of
942 // broken server, which simply stall for a very long time.
943 // We would like to shorten the timeout, but limit this shorter timeout
944 // to the handshake phase.
945 // When we arrive here for the first time (for a given socket),
946 // we know the connection is established, and the application code
947 // tried the first read or write. This triggers the beginning of the
948 // SSL handshake phase at the SSL FD level.
949 // We'll make a note of the current time,
950 // and use this to measure the elapsed time since handshake begin.
952 // Do NOT assume TLS intolerance on a closed connection after bad cert ui was shown.
953 // Simply retry.
954 // This depends on the fact that Cert UI will not be shown again,
955 // should the user override the bad cert.
957 bool handleHandshakeResultNow;
958 socketInfo->GetHandshakePending(&handleHandshakeResultNow);
960 bool wantRetry = false;
962 if (0 > bytesTransfered) {
963 int32_t err = PR_GetError();
965 if (handleHandshakeResultNow) {
966 if (PR_WOULD_BLOCK_ERROR == err) {
967 socketInfo->SetHandshakeInProgress(true);
968 return bytesTransfered;
971 if (!wantRetry // no decision yet
972 && isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
974 nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
975 wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
979 // This is the common place where we trigger non-cert-errors on a SSL
980 // socket. This might be reached at any time of the connection.
982 // The socketInfo->GetErrorCode() check is here to ensure we don't try to
983 // do the synchronous dispatch to the main thread unnecessarily after we've
984 // already handled a certificate error. (SSLErrorRunnable calls
985 // nsHandleSSLError, which has logic to avoid replacing the error message,
986 // so without the !socketInfo->GetErrorCode(), it would just be an
987 // expensive no-op.)
988 if (!wantRetry && (IS_SSL_ERROR(err) || IS_SEC_ERROR(err)) &&
989 !socketInfo->GetErrorCode()) {
990 RefPtr<SyncRunnableBase> runnable(new SSLErrorRunnable(socketInfo,
991 PlainErrorMessage,
992 err));
993 (void) runnable->DispatchToMainThreadAndWait();
996 else if (wasReading && 0 == bytesTransfered) // zero bytes on reading, socket closed
998 if (handleHandshakeResultNow)
1000 if (!wantRetry // no decision yet
1001 && !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
1003 nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
1004 wantRetry = helpers.rememberPossibleTLSProblemSite(socketInfo);
1009 if (wantRetry) {
1010 // We want to cause the network layer to retry the connection.
1011 PR_SetError(PR_CONNECT_RESET_ERROR, 0);
1012 if (wasReading)
1013 bytesTransfered = -1;
1016 // TLS intolerant servers only cause the first transfer to fail, so let's
1017 // set the HandshakePending attribute to false so that we don't try the logic
1018 // above again in a subsequent transfer.
1019 if (handleHandshakeResultNow) {
1020 socketInfo->SetHandshakePending(false);
1021 socketInfo->SetHandshakeInProgress(false);
1024 return bytesTransfered;
1029 static int16_t
1030 nsSSLIOLayerPoll(PRFileDesc * fd, int16_t in_flags, int16_t *out_flags)
1032 nsNSSShutDownPreventionLock locker;
1034 if (!out_flags)
1036 NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
1037 return 0;
1040 *out_flags = 0;
1042 nsNSSSocketInfo * socketInfo =
1043 getSocketInfoIfRunning(fd, not_reading_or_writing, locker);
1045 if (!socketInfo) {
1046 // If we get here, it is probably because certificate validation failed
1047 // and this is the first I/O operation after the failure.
1048 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1049 ("[%p] polling SSL socket right after certificate verification failed "
1050 "or NSS shutdown or SDR logout %d\n",
1051 fd, (int) in_flags));
1053 NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
1054 "caller did not poll for EXCEPT (canceled)");
1055 // Since this poll method cannot return errors, we want the caller to call
1056 // PR_Send/PR_Recv right away to get the error, so we tell that we are
1057 // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
1058 *out_flags = in_flags | PR_POLL_EXCEPT; // see also bug 480619
1059 return in_flags;
1062 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1063 (socketInfo->IsWaitingForCertVerification()
1064 ? "[%p] polling SSL socket during certificate verification using lower %d\n"
1065 : "[%p] poll SSL socket using lower %d\n",
1066 fd, (int) in_flags));
1068 // See comments in HandshakeTimeout before moving and/or changing this block
1069 if (socketInfo->HandshakeTimeout()) {
1070 NS_WARNING("SSL handshake timed out");
1071 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] handshake timed out\n", fd));
1072 NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
1073 "caller did not poll for EXCEPT (handshake timeout)");
1074 *out_flags = in_flags | PR_POLL_EXCEPT;
1075 socketInfo->SetCanceled(PR_CONNECT_RESET_ERROR, PlainErrorMessage);
1076 return in_flags;
1079 // We want the handshake to continue during certificate validation, so we
1080 // don't need to do anything special here. libssl automatically blocks when
1081 // it reaches any point that would be unsafe to send/receive something before
1082 // cert validation is complete.
1083 int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
1084 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
1085 (void*)fd, (int) result));
1086 return result;
1089 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
1090 : mutex(nullptr)
1091 , mTLSIntolerantSites(nullptr)
1092 , mTLSTolerantSites(nullptr)
1093 , mRenegoUnrestrictedSites(nullptr)
1094 , mTreatUnsafeNegotiationAsBroken(false)
1095 , mWarnLevelMissingRFC5746(1)
1099 static int _PSM_InvalidInt(void)
1101 PR_ASSERT(!"I/O method is invalid");
1102 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1103 return -1;
1106 static int64_t _PSM_InvalidInt64(void)
1108 PR_ASSERT(!"I/O method is invalid");
1109 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1110 return -1;
1113 static PRStatus _PSM_InvalidStatus(void)
1115 PR_ASSERT(!"I/O method is invalid");
1116 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1117 return PR_FAILURE;
1120 static PRFileDesc *_PSM_InvalidDesc(void)
1122 PR_ASSERT(!"I/O method is invalid");
1123 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1124 return nullptr;
1127 static PRStatus PSMGetsockname(PRFileDesc *fd, PRNetAddr *addr)
1129 nsNSSShutDownPreventionLock locker;
1130 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1131 return PR_FAILURE;
1133 return fd->lower->methods->getsockname(fd->lower, addr);
1136 static PRStatus PSMGetpeername(PRFileDesc *fd, PRNetAddr *addr)
1138 nsNSSShutDownPreventionLock locker;
1139 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1140 return PR_FAILURE;
1142 return fd->lower->methods->getpeername(fd->lower, addr);
1145 static PRStatus PSMGetsocketoption(PRFileDesc *fd, PRSocketOptionData *data)
1147 nsNSSShutDownPreventionLock locker;
1148 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1149 return PR_FAILURE;
1151 return fd->lower->methods->getsocketoption(fd, data);
1154 static PRStatus PSMSetsocketoption(PRFileDesc *fd,
1155 const PRSocketOptionData *data)
1157 nsNSSShutDownPreventionLock locker;
1158 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1159 return PR_FAILURE;
1161 return fd->lower->methods->setsocketoption(fd, data);
1164 static int32_t PSMRecv(PRFileDesc *fd, void *buf, int32_t amount,
1165 int flags, PRIntervalTime timeout)
1167 nsNSSShutDownPreventionLock locker;
1168 nsNSSSocketInfo *socketInfo = getSocketInfoIfRunning(fd, reading, locker);
1169 if (!socketInfo)
1170 return -1;
1172 if (flags != PR_MSG_PEEK && flags != 0) {
1173 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1174 return -1;
1177 int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
1178 timeout);
1180 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] read %d bytes\n", (void*)fd, bytesRead));
1182 #ifdef DEBUG_SSL_VERBOSE
1183 DEBUG_DUMP_BUFFER((unsigned char*)buf, bytesRead);
1184 #endif
1186 return checkHandshake(bytesRead, true, fd, socketInfo);
1189 static int32_t PSMSend(PRFileDesc *fd, const void *buf, int32_t amount,
1190 int flags, PRIntervalTime timeout)
1192 nsNSSShutDownPreventionLock locker;
1193 nsNSSSocketInfo *socketInfo = getSocketInfoIfRunning(fd, writing, locker);
1194 if (!socketInfo)
1195 return -1;
1197 if (flags != 0) {
1198 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1199 return -1;
1202 #ifdef DEBUG_SSL_VERBOSE
1203 DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
1204 #endif
1206 int32_t bytesWritten = fd->lower->methods->send(fd->lower, buf, amount,
1207 flags, timeout);
1209 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n",
1210 fd, bytesWritten));
1212 return checkHandshake(bytesWritten, false, fd, socketInfo);
1215 static int32_t
1216 nsSSLIOLayerRead(PRFileDesc* fd, void* buf, int32_t amount)
1218 return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1221 static int32_t
1222 nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, int32_t amount)
1224 return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1227 static PRStatus PSMConnectcontinue(PRFileDesc *fd, int16_t out_flags)
1229 nsNSSShutDownPreventionLock locker;
1230 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker)) {
1231 return PR_FAILURE;
1234 return fd->lower->methods->connectcontinue(fd, out_flags);
1237 static int PSMAvailable(void)
1239 // This is called through PR_Available(), but is not implemented in PSM
1240 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1241 return -1;
1244 static int64_t PSMAvailable64(void)
1246 // This is called through PR_Available(), but is not implemented in PSM
1247 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1248 return -1;
1251 namespace {
1252 class PrefObserver : public nsIObserver {
1253 public:
1254 NS_DECL_ISUPPORTS
1255 NS_DECL_NSIOBSERVER
1256 PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
1257 virtual ~PrefObserver() {}
1258 private:
1259 nsSSLIOLayerHelpers* mOwner;
1261 } // namespace anonymous
1263 NS_IMPL_THREADSAFE_ISUPPORTS1(PrefObserver, nsIObserver)
1265 NS_IMETHODIMP
1266 PrefObserver::Observe(nsISupports *aSubject, const char *aTopic,
1267 const PRUnichar *someData)
1269 if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1270 NS_ConvertUTF16toUTF8 prefName(someData);
1272 if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
1273 nsCString unrestricted_hosts;
1274 Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
1275 if (!unrestricted_hosts.IsEmpty()) {
1276 mOwner->setRenegoUnrestrictedSites(unrestricted_hosts);
1278 } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
1279 bool enabled;
1280 Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
1281 mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
1282 } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
1283 int32_t warnLevel = 1;
1284 Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
1285 mOwner->setWarnLevelMissingRFC5746(warnLevel);
1288 return NS_OK;
1291 static int32_t PlaintextRecv(PRFileDesc *fd, void *buf, int32_t amount,
1292 int flags, PRIntervalTime timeout)
1294 // The shutdownlocker is not needed here because it will already be
1295 // held higher in the stack
1296 nsNSSSocketInfo *socketInfo = nullptr;
1298 int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
1299 timeout);
1300 if (fd->identity == nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)
1301 socketInfo = (nsNSSSocketInfo*)fd->secret;
1303 if ((bytesRead > 0) && socketInfo)
1304 socketInfo->AddPlaintextBytesRead(bytesRead);
1305 return bytesRead;
1308 nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
1310 Preferences::RemoveObserver(mPrefObserver, "security.ssl.renego_unrestricted_hosts");
1311 Preferences::RemoveObserver(mPrefObserver, "security.ssl.treat_unsafe_negotiation_as_broken");
1312 Preferences::RemoveObserver(mPrefObserver, "security.ssl.warn_missing_rfc5746");
1315 nsresult nsSSLIOLayerHelpers::Init()
1317 if (!nsSSLIOLayerInitialized) {
1318 nsSSLIOLayerInitialized = true;
1319 nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
1320 nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
1322 nsSSLIOLayerMethods.available = (PRAvailableFN)PSMAvailable;
1323 nsSSLIOLayerMethods.available64 = (PRAvailable64FN)PSMAvailable64;
1324 nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
1325 nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
1326 nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
1327 nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
1328 nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
1329 nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
1330 nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
1331 nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
1332 nsSSLIOLayerMethods.listen = (PRListenFN)_PSM_InvalidStatus;
1333 nsSSLIOLayerMethods.shutdown = (PRShutdownFN)_PSM_InvalidStatus;
1334 nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN)_PSM_InvalidInt;
1335 nsSSLIOLayerMethods.sendto = (PRSendtoFN)_PSM_InvalidInt;
1336 nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN)_PSM_InvalidInt;
1337 nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN)_PSM_InvalidInt;
1338 nsSSLIOLayerMethods.sendfile = (PRSendfileFN)_PSM_InvalidInt;
1340 nsSSLIOLayerMethods.getsockname = PSMGetsockname;
1341 nsSSLIOLayerMethods.getpeername = PSMGetpeername;
1342 nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
1343 nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
1344 nsSSLIOLayerMethods.recv = PSMRecv;
1345 nsSSLIOLayerMethods.send = PSMSend;
1346 nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
1348 nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
1349 nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
1350 nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
1351 nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
1352 nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
1354 nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
1355 nsSSLPlaintextLayerMethods = *PR_GetDefaultIOMethods();
1356 nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
1359 mutex = new Mutex("nsSSLIOLayerHelpers.mutex");
1361 mTLSIntolerantSites = new nsTHashtable<nsCStringHashKey>();
1362 mTLSIntolerantSites->Init(1);
1364 mTLSTolerantSites = new nsTHashtable<nsCStringHashKey>();
1365 // Initialize the tolerant site hashtable to 16 items at the start seems
1366 // reasonable as most servers are TLS tolerant. We just want to lower
1367 // the rate of hashtable array reallocation.
1368 mTLSTolerantSites->Init(16);
1370 mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
1371 mRenegoUnrestrictedSites->Init(1);
1373 nsCString unrestricted_hosts;
1374 Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
1375 if (!unrestricted_hosts.IsEmpty()) {
1376 setRenegoUnrestrictedSites(unrestricted_hosts);
1379 bool enabled = false;
1380 Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
1381 setTreatUnsafeNegotiationAsBroken(enabled);
1383 int32_t warnLevel = 1;
1384 Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
1385 setWarnLevelMissingRFC5746(warnLevel);
1387 mPrefObserver = new PrefObserver(this);
1388 Preferences::AddStrongObserver(mPrefObserver,
1389 "security.ssl.renego_unrestricted_hosts");
1390 Preferences::AddStrongObserver(mPrefObserver,
1391 "security.ssl.treat_unsafe_negotiation_as_broken");
1392 Preferences::AddStrongObserver(mPrefObserver,
1393 "security.ssl.warn_missing_rfc5746");
1395 return NS_OK;
1398 void nsSSLIOLayerHelpers::clearStoredData()
1400 mRenegoUnrestrictedSites->Clear();
1401 mTLSTolerantSites->Clear();
1402 mTLSIntolerantSites->Clear();
1405 void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
1407 MutexAutoLock lock(*mutex);
1408 // Remember intolerant site only if it is not known as tolerant
1409 if (!mTLSTolerantSites->Contains(str))
1410 mTLSIntolerantSites->PutEntry(str);
1413 void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
1415 MutexAutoLock lock(*mutex);
1416 mTLSIntolerantSites->RemoveEntry(str);
1419 bool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
1421 MutexAutoLock lock(*mutex);
1422 return mTLSIntolerantSites->Contains(str);
1425 void nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString &str)
1427 MutexAutoLock lock(*mutex);
1429 if (mRenegoUnrestrictedSites) {
1430 delete mRenegoUnrestrictedSites;
1431 mRenegoUnrestrictedSites = nullptr;
1434 mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
1435 if (!mRenegoUnrestrictedSites)
1436 return;
1438 mRenegoUnrestrictedSites->Init(1);
1440 nsCCharSeparatedTokenizer toker(str, ',');
1442 while (toker.hasMoreTokens()) {
1443 const nsCSubstring &host = toker.nextToken();
1444 if (!host.IsEmpty()) {
1445 mRenegoUnrestrictedSites->PutEntry(host);
1450 bool nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString &str)
1452 MutexAutoLock lock(*mutex);
1453 return mRenegoUnrestrictedSites->Contains(str);
1456 void nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
1458 MutexAutoLock lock(*mutex);
1459 mTreatUnsafeNegotiationAsBroken = broken;
1462 bool nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
1464 MutexAutoLock lock(*mutex);
1465 return mTreatUnsafeNegotiationAsBroken;
1468 void nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(int32_t level)
1470 MutexAutoLock lock(*mutex);
1471 mWarnLevelMissingRFC5746 = level;
1474 int32_t nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746()
1476 MutexAutoLock lock(*mutex);
1477 return mWarnLevelMissingRFC5746;
1480 nsresult
1481 nsSSLIOLayerNewSocket(int32_t family,
1482 const char *host,
1483 int32_t port,
1484 const char *proxyHost,
1485 int32_t proxyPort,
1486 PRFileDesc **fd,
1487 nsISupports** info,
1488 bool forSTARTTLS,
1489 uint32_t flags)
1492 PRFileDesc* sock = PR_OpenTCPSocket(family);
1493 if (!sock) return NS_ERROR_OUT_OF_MEMORY;
1495 nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort,
1496 sock, info, forSTARTTLS, flags);
1497 if (NS_FAILED(rv)) {
1498 PR_Close(sock);
1499 return rv;
1502 *fd = sock;
1503 return NS_OK;
1507 * Function: SECStatus nsConvertCANamesToStrings()
1508 * Purpose: creates CA names strings from (CERTDistNames* caNames)
1510 * Arguments and return values
1511 * - arena: arena to allocate strings on
1512 * - caNameStrings: filled with CA names strings on return
1513 * - caNames: CERTDistNames to extract strings from
1514 * - return: SECSuccess if successful; error code otherwise
1516 * Note: copied in its entirety from Nova code
1518 SECStatus nsConvertCANamesToStrings(PLArenaPool* arena, char** caNameStrings,
1519 CERTDistNames* caNames)
1521 SECItem* dername;
1522 SECStatus rv;
1523 int headerlen;
1524 uint32_t contentlen;
1525 SECItem newitem;
1526 int n;
1527 char* namestring;
1529 for (n = 0; n < caNames->nnames; n++) {
1530 newitem.data = nullptr;
1531 dername = &caNames->names[n];
1533 rv = DER_Lengths(dername, &headerlen, &contentlen);
1535 if (rv != SECSuccess) {
1536 goto loser;
1539 if (headerlen + contentlen != dername->len) {
1540 /* This must be from an enterprise 2.x server, which sent
1541 * incorrectly formatted der without the outer wrapper of
1542 * type and length. Fix it up by adding the top level
1543 * header.
1545 if (dername->len <= 127) {
1546 newitem.data = (unsigned char *) PR_Malloc(dername->len + 2);
1547 if (!newitem.data) {
1548 goto loser;
1550 newitem.data[0] = (unsigned char)0x30;
1551 newitem.data[1] = (unsigned char)dername->len;
1552 (void)memcpy(&newitem.data[2], dername->data, dername->len);
1554 else if (dername->len <= 255) {
1555 newitem.data = (unsigned char *) PR_Malloc(dername->len + 3);
1556 if (!newitem.data) {
1557 goto loser;
1559 newitem.data[0] = (unsigned char)0x30;
1560 newitem.data[1] = (unsigned char)0x81;
1561 newitem.data[2] = (unsigned char)dername->len;
1562 (void)memcpy(&newitem.data[3], dername->data, dername->len);
1564 else {
1565 /* greater than 256, better be less than 64k */
1566 newitem.data = (unsigned char *) PR_Malloc(dername->len + 4);
1567 if (!newitem.data) {
1568 goto loser;
1570 newitem.data[0] = (unsigned char)0x30;
1571 newitem.data[1] = (unsigned char)0x82;
1572 newitem.data[2] = (unsigned char)((dername->len >> 8) & 0xff);
1573 newitem.data[3] = (unsigned char)(dername->len & 0xff);
1574 memcpy(&newitem.data[4], dername->data, dername->len);
1576 dername = &newitem;
1579 namestring = CERT_DerNameToAscii(dername);
1580 if (!namestring) {
1581 /* XXX - keep going until we fail to convert the name */
1582 caNameStrings[n] = const_cast<char*>("");
1584 else {
1585 caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
1586 PR_Free(namestring);
1587 if (!caNameStrings[n]) {
1588 goto loser;
1592 if (newitem.data) {
1593 PR_Free(newitem.data);
1597 return SECSuccess;
1598 loser:
1599 if (newitem.data) {
1600 PR_Free(newitem.data);
1602 return SECFailure;
1606 * structs and ASN1 templates for the limited scope-of-use extension
1608 * CertificateScopeEntry ::= SEQUENCE {
1609 * name GeneralName, -- pattern, as for NameConstraints
1610 * portNumber INTEGER OPTIONAL }
1612 * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry
1615 * CERTCertificateScopeEntry: struct for scope entry that can be consumed by
1616 * the code
1617 * certCertificateScopeOfUse: struct that represents the decoded extension data
1619 typedef struct {
1620 SECItem derConstraint;
1621 SECItem derPort;
1622 CERTGeneralName* constraint; /* decoded constraint */
1623 int port; /* decoded port number */
1624 } CERTCertificateScopeEntry;
1626 typedef struct {
1627 CERTCertificateScopeEntry** entries;
1628 } certCertificateScopeOfUse;
1630 /* corresponding ASN1 templates */
1631 static const SEC_ASN1Template cert_CertificateScopeEntryTemplate[] = {
1632 { SEC_ASN1_SEQUENCE,
1633 0, nullptr, sizeof(CERTCertificateScopeEntry) },
1634 { SEC_ASN1_ANY,
1635 offsetof(CERTCertificateScopeEntry, derConstraint) },
1636 { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
1637 offsetof(CERTCertificateScopeEntry, derPort) },
1638 { 0 }
1641 static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate[] = {
1642 { SEC_ASN1_SEQUENCE_OF, 0, cert_CertificateScopeEntryTemplate }
1645 #if 0
1647 * decodes the extension data and create CERTCertificateScopeEntry that can
1648 * be consumed by the code
1650 static
1651 SECStatus cert_DecodeScopeOfUseEntries(PRArenaPool* arena, SECItem* extData,
1652 CERTCertificateScopeEntry*** entries,
1653 int* numEntries)
1655 certCertificateScopeOfUse* scope = nullptr;
1656 SECStatus rv = SECSuccess;
1657 int i;
1659 *entries = nullptr; /* in case of failure */
1660 *numEntries = 0; /* ditto */
1662 scope = (certCertificateScopeOfUse*)
1663 PORT_ArenaZAlloc(arena, sizeof(certCertificateScopeOfUse));
1664 if (!scope) {
1665 goto loser;
1668 rv = SEC_ASN1DecodeItem(arena, (void*)scope,
1669 cert_CertificateScopeOfUseTemplate, extData);
1670 if (rv != SECSuccess) {
1671 goto loser;
1674 *entries = scope->entries;
1675 PR_ASSERT(*entries);
1677 /* first, let's count 'em. */
1678 for (i = 0; (*entries)[i]; i++) ;
1679 *numEntries = i;
1681 /* convert certCertificateScopeEntry sequence into what we can readily
1682 * use
1684 for (i = 0; i < *numEntries; i++) {
1685 (*entries)[i]->constraint =
1686 CERT_DecodeGeneralName(arena, &((*entries)[i]->derConstraint),
1687 nullptr);
1688 if ((*entries)[i]->derPort.data) {
1689 (*entries)[i]->port =
1690 (int)DER_GetInteger(&((*entries)[i]->derPort));
1692 else {
1693 (*entries)[i]->port = 0;
1697 goto done;
1698 loser:
1699 if (rv == SECSuccess) {
1700 rv = SECFailure;
1702 done:
1703 return rv;
1706 static SECStatus cert_DecodeCertIPAddress(SECItem* genname,
1707 uint32_t* constraint, uint32_t* mask)
1709 /* in case of failure */
1710 *constraint = 0;
1711 *mask = 0;
1713 PR_ASSERT(genname->data);
1714 if (!genname->data) {
1715 return SECFailure;
1717 if (genname->len != 8) {
1718 /* the length must be 4 byte IP address with 4 byte subnet mask */
1719 return SECFailure;
1722 /* get them in the right order */
1723 *constraint = PR_ntohl((uint32_t)(*genname->data));
1724 *mask = PR_ntohl((uint32_t)(*(genname->data + 4)));
1726 return SECSuccess;
1729 static char* _str_to_lower(char* string)
1731 #ifdef XP_WIN
1732 return _strlwr(string);
1733 #else
1734 int i;
1735 for (i = 0; string[i] != '\0'; i++) {
1736 string[i] = tolower(string[i]);
1738 return string;
1739 #endif
1743 * Sees if the client certificate has a restriction in presenting the cert
1744 * to the host: returns true if there is no restriction or if the hostname
1745 * (and the port) satisfies the restriction, or false if the hostname (and
1746 * the port) does not satisfy the restriction
1748 static bool CERT_MatchesScopeOfUse(CERTCertificate* cert, char* hostname,
1749 char* hostIP, int port)
1751 bool rv = true; /* whether the cert can be presented */
1752 SECStatus srv;
1753 SECItem extData;
1754 PLArenaPool* arena = nullptr;
1755 CERTCertificateScopeEntry** entries = nullptr;
1756 /* arrays of decoded scope entries */
1757 int numEntries = 0;
1758 int i;
1759 char* hostLower = nullptr;
1760 uint32_t hostIPAddr = 0;
1762 PR_ASSERT(cert && hostname && hostIP);
1764 /* find cert extension */
1765 srv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
1766 &extData);
1767 if (srv != SECSuccess) {
1768 /* most of the time, this means the extension was not found: also,
1769 * since this is not a critical extension (as of now) we may simply
1770 * return true
1772 goto done;
1775 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1776 if (!arena) {
1777 goto done;
1780 /* decode the scope of use entries into pairs of GeneralNames and
1781 * an optional port numbers
1783 srv = cert_DecodeScopeOfUseEntries(arena, &extData, &entries, &numEntries);
1784 if (srv != SECSuccess) {
1785 /* XXX What should we do when we failed to decode the extension? This
1786 * may mean either the extension was malformed or some (unlikely)
1787 * fatal error on our part: my argument is that if the extension
1788 * was malformed the extension "disqualifies" as a valid
1789 * constraint and we may present the cert
1791 goto done;
1794 /* loop over these structures */
1795 for (i = 0; i < numEntries; i++) {
1796 /* determine whether the GeneralName is a DNS pattern, an IP address
1797 * constraint, or else
1799 CERTGeneralName* genname = entries[i]->constraint;
1801 /* if constraint is nullptr, don't bother looking */
1802 if (!genname) {
1803 /* this is not a failure: just continue */
1804 continue;
1807 switch (genname->type) {
1808 case certDNSName: {
1809 /* we have a DNS name constraint; we should use only the host name
1810 * information
1812 char* pattern = nullptr;
1813 char* substring = nullptr;
1815 /* null-terminate the string */
1816 genname->name.other.data[genname->name.other.len] = '\0';
1817 pattern = _str_to_lower((char*)genname->name.other.data);
1819 if (!hostLower) {
1820 /* so that it's done only if necessary and only once */
1821 hostLower = _str_to_lower(PL_strdup(hostname));
1824 /* the hostname satisfies the constraint */
1825 if (((substring = strstr(hostLower, pattern)) != nullptr) &&
1826 /* the hostname contains the pattern */
1827 (strlen(substring) == strlen(pattern)) &&
1828 /* the hostname ends with the pattern */
1829 ((substring == hostLower) || (*(substring-1) == '.'))) {
1830 /* the hostname either is identical to the pattern or
1831 * belongs to a subdomain
1833 rv = true;
1835 else {
1836 rv = false;
1838 /* clean up strings if necessary */
1839 break;
1841 case certIPAddress: {
1842 uint32_t constraint;
1843 uint32_t mask;
1844 PRNetAddr addr;
1846 if (hostIPAddr == 0) {
1847 /* so that it's done only if necessary and only once */
1848 PR_StringToNetAddr(hostIP, &addr);
1849 hostIPAddr = addr.inet.ip;
1852 if (cert_DecodeCertIPAddress(&(genname->name.other), &constraint,
1853 &mask) != SECSuccess) {
1854 continue;
1856 if ((hostIPAddr & mask) == (constraint & mask)) {
1857 rv = true;
1859 else {
1860 rv = false;
1862 break;
1864 default:
1865 /* ill-formed entry: abort */
1866 continue; /* go to the next entry */
1869 if (!rv) {
1870 /* we do not need to check the port: go to the next entry */
1871 continue;
1874 /* finally, check the optional port number */
1875 if ((entries[i]->port != 0) && (port != entries[i]->port)) {
1876 /* port number does not match */
1877 rv = false;
1878 continue;
1881 /* we have a match */
1882 PR_ASSERT(rv);
1883 break;
1885 done:
1886 /* clean up entries */
1887 if (arena) {
1888 PORT_FreeArena(arena, false);
1890 if (hostLower) {
1891 PR_Free(hostLower);
1893 return rv;
1895 #endif
1898 * Function: SSMStatus SSM_SetUserCertChoice()
1900 * Purpose: sets certChoice by reading the preference
1902 * Arguments and return values
1903 * - conn: SSMSSLDataConnection
1904 * - returns: SSM_SUCCESS if successful; SSM_FAILURE otherwise
1906 * Note: If done properly, this function will read the identifier strings
1907 * for ASK and AUTO modes, read the selected strings from the
1908 * preference, compare the strings, and determine in which mode it is
1909 * in.
1910 * We currently use ASK mode for UI apps and AUTO mode for UI-less
1911 * apps without really asking for preferences.
1913 nsresult nsGetUserCertChoice(SSM_UserCertChoice* certChoice)
1915 char *mode = nullptr;
1916 nsresult ret;
1918 NS_ENSURE_ARG_POINTER(certChoice);
1920 nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
1922 ret = pref->GetCharPref("security.default_personal_cert", &mode);
1923 if (NS_FAILED(ret)) {
1924 goto loser;
1927 if (PL_strcmp(mode, "Select Automatically") == 0) {
1928 *certChoice = AUTO;
1930 else if (PL_strcmp(mode, "Ask Every Time") == 0) {
1931 *certChoice = ASK;
1933 else {
1934 // Most likely we see a nickname from a migrated cert.
1935 // We do not currently support that, ask the user which cert to use.
1936 *certChoice = ASK;
1939 loser:
1940 if (mode) {
1941 nsMemory::Free(mode);
1943 return ret;
1946 static bool hasExplicitKeyUsageNonRepudiation(CERTCertificate *cert)
1948 /* There is no extension, v1 or v2 certificate */
1949 if (!cert->extensions)
1950 return false;
1952 SECStatus srv;
1953 SECItem keyUsageItem;
1954 keyUsageItem.data = nullptr;
1956 srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
1957 if (srv == SECFailure)
1958 return false;
1960 unsigned char keyUsage = keyUsageItem.data[0];
1961 PORT_Free (keyUsageItem.data);
1963 return !!(keyUsage & KU_NON_REPUDIATION);
1966 class ClientAuthDataRunnable : public SyncRunnableBase
1968 public:
1969 ClientAuthDataRunnable(CERTDistNames* caNames,
1970 CERTCertificate** pRetCert,
1971 SECKEYPrivateKey** pRetKey,
1972 nsNSSSocketInfo * info,
1973 CERTCertificate * serverCert)
1974 : mRV(SECFailure)
1975 , mErrorCodeToReport(SEC_ERROR_NO_MEMORY)
1976 , mPRetCert(pRetCert)
1977 , mPRetKey(pRetKey)
1978 , mCANames(caNames)
1979 , mSocketInfo(info)
1980 , mServerCert(serverCert)
1984 SECStatus mRV; // out
1985 PRErrorCode mErrorCodeToReport; // out
1986 CERTCertificate** const mPRetCert; // in/out
1987 SECKEYPrivateKey** const mPRetKey; // in/out
1988 protected:
1989 virtual void RunOnTargetThread();
1990 private:
1991 CERTDistNames* const mCANames; // in
1992 nsNSSSocketInfo * const mSocketInfo; // in
1993 CERTCertificate * const mServerCert; // in
1997 * Function: SECStatus SSM_SSLGetClientAuthData()
1998 * Purpose: this callback function is used to pull client certificate
1999 * information upon server request
2001 * Arguments and return values
2002 * - arg: SSL data connection
2003 * - socket: SSL socket we're dealing with
2004 * - caNames: list of CA names
2005 * - pRetCert: returns a pointer to a pointer to a valid certificate if
2006 * successful; otherwise NULL
2007 * - pRetKey: returns a pointer to a pointer to the corresponding key if
2008 * successful; otherwise NULL
2009 * - returns: SECSuccess if successful; error code otherwise
2011 SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
2012 CERTDistNames* caNames,
2013 CERTCertificate** pRetCert,
2014 SECKEYPrivateKey** pRetKey)
2016 nsNSSShutDownPreventionLock locker;
2018 if (!socket || !caNames || !pRetCert || !pRetKey) {
2019 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2020 return SECFailure;
2023 RefPtr<nsNSSSocketInfo> info(
2024 reinterpret_cast<nsNSSSocketInfo*>(socket->higher->secret));
2026 CERTCertificate* serverCert = SSL_PeerCertificate(socket);
2027 if (!serverCert) {
2028 NS_NOTREACHED("Missing server certificate should have been detected during "
2029 "server cert authentication.");
2030 PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
2031 return SECFailure;
2034 if (info->GetJoined()) {
2035 // We refuse to send a client certificate when there are multiple hostnames
2036 // joined on this connection, because we only show the user one hostname
2037 // (mHostName) in the client certificate UI.
2039 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
2040 ("[%p] Not returning client cert due to previous join\n", socket));
2041 *pRetCert = nullptr;
2042 *pRetKey = nullptr;
2043 return SECSuccess;
2046 // XXX: This should be done asynchronously; see bug 696976
2047 RefPtr<ClientAuthDataRunnable> runnable(
2048 new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert));
2049 nsresult rv = runnable->DispatchToMainThreadAndWait();
2050 if (NS_FAILED(rv)) {
2051 PR_SetError(SEC_ERROR_NO_MEMORY, 0);
2052 return SECFailure;
2055 if (runnable->mRV != SECSuccess) {
2056 PR_SetError(runnable->mErrorCodeToReport, 0);
2057 } else if (*runnable->mPRetCert || *runnable->mPRetKey) {
2058 // Make joinConnection prohibit joining after we've sent a client cert
2059 info->SetSentClientCert();
2062 return runnable->mRV;
2065 void ClientAuthDataRunnable::RunOnTargetThread()
2067 PLArenaPool* arena = nullptr;
2068 char** caNameStrings;
2069 ScopedCERTCertificate cert;
2070 ScopedSECKEYPrivateKey privKey;
2071 ScopedCERTCertList certList;
2072 CERTCertListNode* node;
2073 ScopedCERTCertNicknames nicknames;
2074 char* extracted = nullptr;
2075 int keyError = 0; /* used for private key retrieval error */
2076 SSM_UserCertChoice certChoice;
2077 int32_t NumberOfCerts = 0;
2078 void * wincx = mSocketInfo;
2079 nsresult rv;
2081 /* create caNameStrings */
2082 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2083 if (!arena) {
2084 goto loser;
2087 caNameStrings = (char**)PORT_ArenaAlloc(arena,
2088 sizeof(char*)*(mCANames->nnames));
2089 if (!caNameStrings) {
2090 goto loser;
2093 mRV = nsConvertCANamesToStrings(arena, caNameStrings, mCANames);
2094 if (mRV != SECSuccess) {
2095 goto loser;
2098 /* get the preference */
2099 if (NS_FAILED(nsGetUserCertChoice(&certChoice))) {
2100 goto loser;
2103 /* find valid user cert and key pair */
2104 if (certChoice == AUTO) {
2105 /* automatically find the right cert */
2107 /* find all user certs that are valid and for SSL */
2108 certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
2109 certUsageSSLClient, false,
2110 true, wincx);
2111 if (!certList) {
2112 goto noCert;
2115 /* filter the list to those issued by CAs supported by the server */
2116 mRV = CERT_FilterCertListByCANames(certList, mCANames->nnames,
2117 caNameStrings, certUsageSSLClient);
2118 if (mRV != SECSuccess) {
2119 goto noCert;
2122 /* make sure the list is not empty */
2123 node = CERT_LIST_HEAD(certList);
2124 if (CERT_LIST_END(node, certList)) {
2125 goto noCert;
2128 ScopedCERTCertificate low_prio_nonrep_cert;
2130 /* loop through the list until we find a cert with a key */
2131 while (!CERT_LIST_END(node, certList)) {
2132 /* if the certificate has restriction and we do not satisfy it
2133 * we do not use it
2135 #if 0 /* XXX This must be re-enabled */
2136 if (!CERT_MatchesScopeOfUse(node->cert, mSocketInfo->GetHostName,
2137 info->GetHostIP, info->GetHostPort)) {
2138 node = CERT_LIST_NEXT(node);
2139 continue;
2141 #endif
2143 privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
2144 if (privKey) {
2145 if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
2146 privKey = nullptr;
2147 // Not a prefered cert
2148 if (!low_prio_nonrep_cert) // did not yet find a low prio cert
2149 low_prio_nonrep_cert = CERT_DupCertificate(node->cert);
2151 else {
2152 // this is a good cert to present
2153 cert = CERT_DupCertificate(node->cert);
2154 break;
2157 keyError = PR_GetError();
2158 if (keyError == SEC_ERROR_BAD_PASSWORD) {
2159 /* problem with password: bail */
2160 goto loser;
2163 node = CERT_LIST_NEXT(node);
2166 if (!cert && low_prio_nonrep_cert) {
2167 cert = low_prio_nonrep_cert.forget();
2168 privKey = PK11_FindKeyByAnyCert(cert, wincx);
2171 if (!cert) {
2172 goto noCert;
2175 else { // Not Auto => ask
2176 /* Get the SSL Certificate */
2178 nsXPIDLCString hostname;
2179 mSocketInfo->GetHostName(getter_Copies(hostname));
2181 RefPtr<nsClientAuthRememberService> cars =
2182 mSocketInfo->SharedState().GetClientAuthRememberService();
2184 bool hasRemembered = false;
2185 nsCString rememberedDBKey;
2186 if (cars) {
2187 bool found;
2188 rv = cars->HasRememberedDecision(hostname, mServerCert,
2189 rememberedDBKey, &found);
2190 if (NS_SUCCEEDED(rv) && found) {
2191 hasRemembered = true;
2195 bool canceled = false;
2197 if (hasRemembered)
2199 if (rememberedDBKey.IsEmpty())
2201 canceled = true;
2203 else
2205 nsCOMPtr<nsIX509CertDB> certdb;
2206 certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
2207 if (certdb)
2209 nsCOMPtr<nsIX509Cert> found_cert;
2210 nsresult find_rv =
2211 certdb->FindCertByDBKey(rememberedDBKey.get(), nullptr,
2212 getter_AddRefs(found_cert));
2213 if (NS_SUCCEEDED(find_rv) && found_cert) {
2214 nsNSSCertificate *obj_cert = reinterpret_cast<nsNSSCertificate *>(found_cert.get());
2215 if (obj_cert) {
2216 cert = obj_cert->GetCert();
2218 #ifdef DEBUG_kaie
2219 nsAutoString nick, nickWithSerial, details;
2220 if (NS_SUCCEEDED(obj_cert->FormatUIStrings(nick,
2221 nickWithSerial,
2222 details))) {
2223 NS_LossyConvertUTF16toASCII asc(nickWithSerial);
2224 fprintf(stderr, "====> remembered serial %s\n", asc.get());
2226 #endif
2231 if (!cert) {
2232 hasRemembered = false;
2238 if (!hasRemembered)
2240 /* user selects a cert to present */
2241 nsIClientAuthDialogs *dialogs = nullptr;
2242 int32_t selectedIndex = -1;
2243 PRUnichar **certNicknameList = nullptr;
2244 PRUnichar **certDetailsList = nullptr;
2246 /* find all user certs that are for SSL */
2247 /* note that we are allowing expired certs in this list */
2248 certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
2249 certUsageSSLClient, false,
2250 false, wincx);
2251 if (!certList) {
2252 goto noCert;
2255 if (mCANames->nnames != 0) {
2256 /* filter the list to those issued by CAs supported by the
2257 * server
2259 mRV = CERT_FilterCertListByCANames(certList, mCANames->nnames,
2260 caNameStrings,
2261 certUsageSSLClient);
2262 if (mRV != SECSuccess) {
2263 goto loser;
2267 if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
2268 /* list is empty - no matching certs */
2269 goto noCert;
2272 /* filter it further for hostname restriction */
2273 node = CERT_LIST_HEAD(certList);
2274 while (!CERT_LIST_END(node, certList)) {
2275 ++NumberOfCerts;
2276 #if 0 /* XXX Fix this */
2277 if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName,
2278 conn->hostIP, conn->port)) {
2279 CERTCertListNode* removed = node;
2280 node = CERT_LIST_NEXT(removed);
2281 CERT_RemoveCertListNode(removed);
2283 else {
2284 node = CERT_LIST_NEXT(node);
2286 #endif
2287 node = CERT_LIST_NEXT(node);
2289 if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
2290 goto noCert;
2293 nicknames = getNSSCertNicknamesFromCertList(certList);
2295 if (!nicknames) {
2296 goto loser;
2299 NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");
2301 /* Get CN and O of the subject and O of the issuer */
2302 char *ccn = CERT_GetCommonName(&mServerCert->subject);
2303 void *v = ccn;
2304 voidCleaner ccnCleaner(v);
2305 NS_ConvertUTF8toUTF16 cn(ccn);
2307 int32_t port;
2308 mSocketInfo->GetPort(&port);
2310 nsString cn_host_port;
2311 if (ccn && strcmp(ccn, hostname) == 0) {
2312 cn_host_port.Append(cn);
2313 cn_host_port.AppendLiteral(":");
2314 cn_host_port.AppendInt(port);
2316 else {
2317 cn_host_port.Append(cn);
2318 cn_host_port.AppendLiteral(" (");
2319 cn_host_port.AppendLiteral(":");
2320 cn_host_port.AppendInt(port);
2321 cn_host_port.AppendLiteral(")");
2324 char *corg = CERT_GetOrgName(&mServerCert->subject);
2325 NS_ConvertUTF8toUTF16 org(corg);
2326 if (corg) PORT_Free(corg);
2328 char *cissuer = CERT_GetOrgName(&mServerCert->issuer);
2329 NS_ConvertUTF8toUTF16 issuer(cissuer);
2330 if (cissuer) PORT_Free(cissuer);
2332 certNicknameList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
2333 if (!certNicknameList)
2334 goto loser;
2335 certDetailsList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
2336 if (!certDetailsList) {
2337 nsMemory::Free(certNicknameList);
2338 goto loser;
2341 int32_t CertsToUse;
2342 for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
2343 !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
2344 node = CERT_LIST_NEXT(node)
2347 RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
2349 if (!tempCert)
2350 continue;
2352 NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
2353 nsAutoString nickWithSerial, details;
2355 if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
2356 continue;
2358 certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
2359 if (!certNicknameList[CertsToUse])
2360 continue;
2361 certDetailsList[CertsToUse] = ToNewUnicode(details);
2362 if (!certDetailsList[CertsToUse]) {
2363 nsMemory::Free(certNicknameList[CertsToUse]);
2364 continue;
2367 ++CertsToUse;
2370 /* Throw up the client auth dialog and get back the index of the selected cert */
2371 nsresult rv = getNSSDialogs((void**)&dialogs,
2372 NS_GET_IID(nsIClientAuthDialogs),
2373 NS_CLIENTAUTHDIALOGS_CONTRACTID);
2375 if (NS_FAILED(rv)) {
2376 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
2377 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
2378 goto loser;
2382 nsPSMUITracker tracker;
2383 if (tracker.isUIForbidden()) {
2384 rv = NS_ERROR_NOT_AVAILABLE;
2386 else {
2387 rv = dialogs->ChooseCertificate(mSocketInfo, cn_host_port.get(),
2388 org.get(), issuer.get(),
2389 (const PRUnichar**)certNicknameList,
2390 (const PRUnichar**)certDetailsList,
2391 CertsToUse, &selectedIndex, &canceled);
2395 NS_RELEASE(dialogs);
2396 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
2397 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
2399 if (NS_FAILED(rv)) goto loser;
2401 // even if the user has canceled, we want to remember that, to avoid repeating prompts
2402 bool wantRemember = false;
2403 mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
2405 int i;
2406 if (!canceled)
2407 for (i = 0, node = CERT_LIST_HEAD(certList);
2408 !CERT_LIST_END(node, certList);
2409 ++i, node = CERT_LIST_NEXT(node)) {
2411 if (i == selectedIndex) {
2412 cert = CERT_DupCertificate(node->cert);
2413 break;
2417 if (cars && wantRemember) {
2418 cars->RememberDecision(hostname, mServerCert,
2419 canceled ? nullptr : cert.get());
2423 if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
2425 if (!cert) {
2426 goto loser;
2429 /* go get the private key */
2430 privKey = PK11_FindKeyByAnyCert(cert, wincx);
2431 if (!privKey) {
2432 keyError = PR_GetError();
2433 if (keyError == SEC_ERROR_BAD_PASSWORD) {
2434 /* problem with password: bail */
2435 goto loser;
2437 else {
2438 goto noCert;
2442 goto done;
2444 noCert:
2445 loser:
2446 if (mRV == SECSuccess) {
2447 mRV = SECFailure;
2449 done:
2450 int error = PR_GetError();
2452 if (extracted) {
2453 PR_Free(extracted);
2455 if (arena) {
2456 PORT_FreeArena(arena, false);
2459 *mPRetCert = cert.forget();
2460 *mPRetKey = privKey.forget();
2462 if (mRV == SECFailure) {
2463 mErrorCodeToReport = error;
2467 static PRFileDesc*
2468 nsSSLIOLayerImportFD(PRFileDesc *fd,
2469 nsNSSSocketInfo *infoObject,
2470 const char *host)
2472 nsNSSShutDownPreventionLock locker;
2473 PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd);
2474 if (!sslSock) {
2475 NS_ASSERTION(false, "NSS: Error importing socket");
2476 return nullptr;
2478 SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
2479 SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
2481 // Disable this hook if we connect anonymously. See bug 466080.
2482 uint32_t flags = 0;
2483 infoObject->GetProviderFlags(&flags);
2484 if (flags & nsISocketProvider::ANONYMOUS_CONNECT) {
2485 SSL_GetClientAuthDataHook(sslSock, nullptr, infoObject);
2486 } else {
2487 SSL_GetClientAuthDataHook(sslSock,
2488 (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData,
2489 infoObject);
2491 if (SECSuccess != SSL_AuthCertificateHook(sslSock, AuthCertificateHook,
2492 infoObject)) {
2493 NS_NOTREACHED("failed to configure AuthCertificateHook");
2494 goto loser;
2497 if (SECSuccess != SSL_SetURL(sslSock, host)) {
2498 NS_NOTREACHED("SSL_SetURL failed");
2499 goto loser;
2502 // This is an optimization to make sure the identity info dataset is parsed
2503 // and loaded on a separate thread and can be overlapped with network latency.
2504 EnsureServerVerificationInitialized();
2506 return sslSock;
2507 loser:
2508 if (sslSock) {
2509 PR_Close(sslSock);
2511 return nullptr;
2514 static nsresult
2515 nsSSLIOLayerSetOptions(PRFileDesc *fd, bool forSTARTTLS,
2516 const char *proxyHost, const char *host, int32_t port,
2517 nsNSSSocketInfo *infoObject)
2519 nsNSSShutDownPreventionLock locker;
2520 if (forSTARTTLS || proxyHost) {
2521 if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
2522 return NS_ERROR_FAILURE;
2524 infoObject->SetHasCleartextPhase(true);
2527 // Let's see if we're trying to connect to a site we know is
2528 // TLS intolerant.
2529 nsAutoCString key;
2530 key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
2532 if (infoObject->SharedState().IOLayerHelpers().isKnownAsIntolerantSite(key)) {
2533 if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, false))
2534 return NS_ERROR_FAILURE;
2536 infoObject->SetAllowTLSIntoleranceTimeout(false);
2538 // We assume that protocols that use the STARTTLS mechanism should support
2539 // modern hellos. For other protocols, if we suspect a site
2540 // does not support TLS, let's also use V2 hellos.
2541 // One advantage of this approach, if a site only supports the older
2542 // hellos, it is more likely that we will get a reasonable error code
2543 // on our single retry attempt.
2546 PRBool enabled;
2547 if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_SSL3, &enabled)) {
2548 return NS_ERROR_FAILURE;
2550 infoObject->SetSSL3Enabled(enabled);
2551 if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_TLS, &enabled)) {
2552 return NS_ERROR_FAILURE;
2554 infoObject->SetTLSEnabled(enabled);
2556 enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
2557 if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) {
2558 return NS_ERROR_FAILURE;
2561 if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
2562 return NS_ERROR_FAILURE;
2565 nsSSLIOLayerHelpers& ioHelpers = infoObject->SharedState().IOLayerHelpers();
2566 if (ioHelpers.isRenegoUnrestrictedSite(nsDependentCString(host))) {
2567 if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
2568 return NS_ERROR_FAILURE;
2570 if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED)) {
2571 return NS_ERROR_FAILURE;
2575 // Set the Peer ID so that SSL proxy connections work properly and to
2576 // separate anonymous and/or private browsing connections.
2577 uint32_t flags = infoObject->GetProviderFlags();
2578 nsAutoCString peerId;
2579 if (flags & nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
2580 peerId.Append("anon:");
2582 if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
2583 peerId.Append("private:");
2585 peerId.Append(host);
2586 peerId.Append(':');
2587 peerId.AppendInt(port);
2588 if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
2589 return NS_ERROR_FAILURE;
2592 return NS_OK;
2595 nsresult
2596 nsSSLIOLayerAddToSocket(int32_t family,
2597 const char* host,
2598 int32_t port,
2599 const char* proxyHost,
2600 int32_t proxyPort,
2601 PRFileDesc* fd,
2602 nsISupports** info,
2603 bool forSTARTTLS,
2604 uint32_t providerFlags)
2606 nsNSSShutDownPreventionLock locker;
2607 PRFileDesc* layer = nullptr;
2608 PRFileDesc* plaintextLayer = nullptr;
2609 nsresult rv;
2610 PRStatus stat;
2612 SharedSSLState* sharedState =
2613 providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ? PrivateSSLState() : PublicSSLState();
2614 nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
2615 if (!infoObject) return NS_ERROR_FAILURE;
2617 NS_ADDREF(infoObject);
2618 infoObject->SetForSTARTTLS(forSTARTTLS);
2619 infoObject->SetHostName(host);
2620 infoObject->SetPort(port);
2622 // A plaintext observer shim is inserted so we can observe some protocol
2623 // details without modifying nss
2624 plaintextLayer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity,
2625 &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods);
2626 if (plaintextLayer) {
2627 plaintextLayer->secret = (PRFilePrivate*) infoObject;
2628 stat = PR_PushIOLayer(fd, PR_TOP_IO_LAYER, plaintextLayer);
2629 if (stat == PR_FAILURE) {
2630 plaintextLayer->dtor(plaintextLayer);
2631 plaintextLayer = nullptr;
2635 PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
2636 if (!sslSock) {
2637 NS_ASSERTION(false, "NSS: Error importing socket");
2638 goto loser;
2641 infoObject->SetFileDescPtr(sslSock);
2643 rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, proxyHost, host, port,
2644 infoObject);
2646 if (NS_FAILED(rv))
2647 goto loser;
2649 /* Now, layer ourselves on top of the SSL socket... */
2650 layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
2651 &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
2652 if (!layer)
2653 goto loser;
2655 layer->secret = (PRFilePrivate*) infoObject;
2656 stat = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
2658 if (stat == PR_FAILURE) {
2659 goto loser;
2662 nsNSSShutDownList::trackSSLSocketCreate();
2664 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*)sslSock));
2665 infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
2667 // We are going use a clear connection first //
2668 if (forSTARTTLS || proxyHost) {
2669 infoObject->SetHandshakePending(false);
2672 infoObject->SharedState().NoteSocketCreated();
2674 return NS_OK;
2675 loser:
2676 NS_IF_RELEASE(infoObject);
2677 if (layer) {
2678 layer->dtor(layer);
2680 if (plaintextLayer) {
2681 PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
2682 plaintextLayer->dtor(plaintextLayer);
2684 return NS_ERROR_FAILURE;