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"
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"
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"
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
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
70 extern PRLogModuleInfo
* gPIPNSSLog
;
73 nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState
& aState
, uint32_t providerFlags
)
75 mCertVerificationState(before_cert_verification
),
80 mHandshakePending(true),
81 mHasCleartextPhase(false),
82 mHandshakeInProgress(false),
83 mAllowTLSIntoleranceTimeout(true),
84 mRememberClientAuthCertificate(false),
85 mHandshakeStartTime(0),
86 mFirstServerHelloReceived(false),
88 mHandshakeCompleted(false),
90 mSentClientCert(false),
91 mProviderFlags(providerFlags
),
92 mSocketCreationTimestamp(TimeStamp::Now()),
93 mPlaintextBytesRead(0)
97 NS_IMPL_ISUPPORTS_INHERITED2(nsNSSSocketInfo
, TransportSecurityInfo
,
99 nsIClientAuthUserDecision
)
102 nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags
)
104 *aProviderFlags
= mProviderFlags
;
109 nsNSSSocketInfo::GetHandshakePending(bool *aHandshakePending
)
111 *aHandshakePending
= mHandshakePending
;
116 nsNSSSocketInfo::SetHandshakePending(bool aHandshakePending
)
118 mHandshakePending
= aHandshakePending
;
122 NS_IMETHODIMP
nsNSSSocketInfo::GetRememberClientAuthCertificate(bool *aRememberClientAuthCertificate
)
124 NS_ENSURE_ARG_POINTER(aRememberClientAuthCertificate
);
125 *aRememberClientAuthCertificate
= mRememberClientAuthCertificate
;
129 NS_IMETHODIMP
nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRememberClientAuthCertificate
)
131 mRememberClientAuthCertificate
= aRememberClientAuthCertificate
;
135 void nsNSSSocketInfo::SetHasCleartextPhase(bool aHasCleartextPhase
)
137 mHasCleartextPhase
= aHasCleartextPhase
;
140 bool nsNSSSocketInfo::GetHasCleartextPhase()
142 return mHasCleartextPhase
;
146 nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor
** aCallbacks
)
148 *aCallbacks
= mCallbacks
;
149 NS_IF_ADDREF(*aCallbacks
);
154 nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor
* aCallbacks
)
157 mCallbacks
= nullptr;
161 mCallbacks
= aCallbacks
;
166 #ifndef NSS_NO_LIBPKIX
168 getSecureBrowserUI(nsIInterfaceRequestor
* callbacks
,
169 nsISecureBrowserUI
** result
)
171 NS_ASSERTION(result
, "result parameter to getSecureBrowserUI is null");
174 NS_ASSERTION(NS_IsMainThread(),
175 "getSecureBrowserUI called off the main thread");
180 nsCOMPtr
<nsISecureBrowserUI
> secureUI
= do_GetInterface(callbacks
);
182 secureUI
.forget(result
);
186 nsCOMPtr
<nsIDocShellTreeItem
> item
= do_GetInterface(callbacks
);
188 nsCOMPtr
<nsIDocShellTreeItem
> rootItem
;
189 (void) item
->GetSameTypeRootTreeItem(getter_AddRefs(rootItem
));
191 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryInterface(rootItem
);
193 (void) docShell
->GetSecurityUI(result
);
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;
226 nsNSSSocketInfo::SetNegotiatedNPN(const char *value
, uint32_t length
)
229 mNegotiatedNPN
.Truncate();
231 mNegotiatedNPN
.Assign(value
, length
);
232 mNPNCompleted
= true;
236 nsNSSSocketInfo::GetNegotiatedNPN(nsACString
&aNegotiatedNPN
)
239 return NS_ERROR_NOT_CONNECTED
;
241 aNegotiatedNPN
= mNegotiatedNPN
;
246 nsNSSSocketInfo::JoinConnection(const nsACString
& npnProtocol
,
247 const nsACString
& hostname
,
253 // Different ports may not be joined together
254 if (port
!= GetPort())
257 // Make sure NPN has been completed and matches requested npnProtocol
258 if (!mNPNCompleted
|| !mNegotiatedNPN
.Equals(npnProtocol
))
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())) {
268 // Before checking the server certificate we need to make sure the
269 // handshake has completed.
270 if (!mHandshakeCompleted
|| !SSLStatus() || !SSLStatus()->mServerCert
)
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
)
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
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
);
292 nssCert
= cert2
->GetCert();
297 if (CERT_VerifyCertName(nssCert
, PromiseFlatCString(hostname
).get()) !=
301 // All tests pass - this is joinable
308 nsNSSSocketInfo::GetForSTARTTLS(bool* aForSTARTTLS
)
310 *aForSTARTTLS
= mForSTARTTLS
;
315 nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS
)
317 mForSTARTTLS
= aForSTARTTLS
;
322 nsNSSSocketInfo::ProxyStartSSL()
324 return ActivateSSL();
328 nsNSSSocketInfo::StartTLS()
330 return ActivateSSL();
334 nsNSSSocketInfo::SetNPNList(nsTArray
<nsCString
> &protocolArray
)
336 nsNSSShutDownPreventionLock locker
;
337 if (isAlreadyShutDown())
338 return NS_ERROR_NOT_AVAILABLE
;
340 return NS_ERROR_FAILURE
;
342 // the npn list is a concatenated list of 8 bit byte strings.
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(
356 reinterpret_cast<const unsigned char *>(npnList
.get()),
357 npnList
.Length()) != SECSuccess
)
358 return NS_ERROR_FAILURE
;
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;
379 nsresult
nsNSSSocketInfo::GetFileDescPtr(PRFileDesc
** aFilePtr
)
385 nsresult
nsNSSSocketInfo::SetFileDescPtr(PRFileDesc
* aFilePtr
)
391 #ifndef NSS_NO_LIBPKIX
392 class PreviousCertRunnable
: public SyncRunnableBase
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
));
409 (void) status
->GetServerCert(getter_AddRefs(mPreviousCert
));
414 nsCOMPtr
<nsIX509Cert
> mPreviousCert
; // out
416 nsCOMPtr
<nsIInterfaceRequestor
> mCallbacks
; // in
420 void nsNSSSocketInfo::GetPreviousCert(nsIX509Cert
** _result
)
422 NS_ASSERTION(_result
, "_result parameter to GetPreviousCert is null");
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
);
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
449 nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode
,
450 SSLErrorMessageType errorMessageType
)
452 NS_ASSERTION(mCertVerificationState
== waiting_for_cert_verification
,
453 "Invalid state transition to cert_verification_finished");
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
;
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()
499 bool nsNSSSocketInfo::HandshakeTimeout()
501 if (!mAllowTLSIntoleranceTimeout
)
504 if (!mHandshakeInProgress
)
505 return false; // have not even sent client hello yet
507 if (mFirstServerHelloReceived
)
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
;
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;
549 nsHandleSSLError(nsNSSSocketInfo
*socketInfo
,
550 ::mozilla::psm::SSLErrorMessageType errtype
,
553 if (!NS_IsMainThread()) {
554 NS_ERROR("nsHandleSSLError called off the main thread");
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.
569 NS_DEFINE_CID(nssComponentCID
, NS_NSSCOMPONENT_CID
);
570 nsCOMPtr
<nsINSSComponent
> nssComponent(do_GetService(nssComponentCID
, &rv
));
574 nsXPIDLCString hostName
;
575 socketInfo
->GetHostName(getter_Copies(hostName
));
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
));
584 nsCOMPtr
<nsISSLErrorListener
> sel
= do_GetInterface(cb
);
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
);
605 console
->LogStringMessage(errorString
.get());
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
);
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);
629 nsNSSSocketInfo
*socketInfo
= (nsNSSSocketInfo
*)fd
->secret
;
631 if (socketInfo
->isAlreadyShutDown() || socketInfo
->isPK11LoggedOut()) {
632 PR_SetError(PR_SOCKET_SHUTDOWN_ERROR
, 0);
636 if (socketInfo
->GetErrorCode()) {
637 PRErrorCode err
= socketInfo
->GetErrorCode();
639 if (op
== reading
|| op
== writing
) {
640 // We must do TLS intolerance checks for reads and writes, for timeouts
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.
653 } // unnnamed namespace
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
))
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()));
671 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
, ("[%p] Connect\n", (void*)fd
));
676 nsSSLIOLayerHelpers::getSiteKey(nsNSSSocketInfo
*socketInfo
, nsCSubstring
&key
)
679 socketInfo
->GetPort(&port
);
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.
692 nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(nsNSSSocketInfo
*socketInfo
)
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
);
706 if (socketInfo
->IsSSL3Enabled()) {
707 // Add this site to the list of TLS intolerant sites.
708 addIntolerantSite(key
);
711 return false; // doesn't make sense to retry
714 return socketInfo
->IsTLSEnabled();
718 nsSSLIOLayerHelpers::rememberTolerantSite(nsNSSSocketInfo
*socketInfo
)
720 if (!socketInfo
->IsTLSEnabled())
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
;
737 nsSSLIOLayerClose(PRFileDesc
*fd
)
739 nsNSSShutDownPreventionLock locker
;
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.
778 if (status
!= PR_SUCCESS
) return status
;
780 popped
->identity
= PR_INVALID_IO_LAYER
;
782 popped
->dtor(popped
);
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
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";
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
);
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
);
823 /* Convert a character to hex. */
824 *h
++ = hex
[(ch
>> 4) & 0xf];
825 *h
++ = hex
[ch
& 0xf];
828 /* Put the character (if it's printable) into the character buffer. */
829 if ((ch
>= 0x20) && (ch
<= 0x7e))
835 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
, ("%s%s\n", hexbuf
, chrbuf
));
838 #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
840 #define DEBUG_DUMP_BUFFER(buf,len)
844 isNonSSLErrorThatWeAllowToRetry(int32_t err
, bool withInitialCleartext
)
848 case PR_CONNECT_RESET_ERROR
:
849 if (!withInitialCleartext
)
853 case PR_END_OF_FILE_ERROR
:
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
))
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
:
898 class SSLErrorRunnable
: public SyncRunnableBase
901 SSLErrorRunnable(nsNSSSocketInfo
* infoObject
,
902 ::mozilla::psm::SSLErrorMessageType errtype
,
903 PRErrorCode errorCode
)
904 : mInfoObject(infoObject
)
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
;
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
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.
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
988 if (!wantRetry
&& (IS_SSL_ERROR(err
) || IS_SEC_ERROR(err
)) &&
989 !socketInfo
->GetErrorCode()) {
990 RefPtr
<SyncRunnableBase
> runnable(new SSLErrorRunnable(socketInfo
,
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
);
1010 // We want to cause the network layer to retry the connection.
1011 PR_SetError(PR_CONNECT_RESET_ERROR
, 0);
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
;
1030 nsSSLIOLayerPoll(PRFileDesc
* fd
, int16_t in_flags
, int16_t *out_flags
)
1032 nsNSSShutDownPreventionLock locker
;
1036 NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
1042 nsNSSSocketInfo
* socketInfo
=
1043 getSocketInfoIfRunning(fd
, not_reading_or_writing
, locker
);
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
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
);
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
));
1089 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
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);
1106 static int64_t _PSM_InvalidInt64(void)
1108 PR_ASSERT(!"I/O method is invalid");
1109 PR_SetError(PR_INVALID_METHOD_ERROR
, 0);
1113 static PRStatus
_PSM_InvalidStatus(void)
1115 PR_ASSERT(!"I/O method is invalid");
1116 PR_SetError(PR_INVALID_METHOD_ERROR
, 0);
1120 static PRFileDesc
*_PSM_InvalidDesc(void)
1122 PR_ASSERT(!"I/O method is invalid");
1123 PR_SetError(PR_INVALID_METHOD_ERROR
, 0);
1127 static PRStatus
PSMGetsockname(PRFileDesc
*fd
, PRNetAddr
*addr
)
1129 nsNSSShutDownPreventionLock locker
;
1130 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
, locker
))
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
))
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
))
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
))
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
);
1172 if (flags
!= PR_MSG_PEEK
&& flags
!= 0) {
1173 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
1177 int32_t bytesRead
= fd
->lower
->methods
->recv(fd
->lower
, buf
, amount
, flags
,
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
);
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
);
1198 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
1202 #ifdef DEBUG_SSL_VERBOSE
1203 DEBUG_DUMP_BUFFER((unsigned char*)buf
, amount
);
1206 int32_t bytesWritten
= fd
->lower
->methods
->send(fd
->lower
, buf
, amount
,
1209 PR_LOG(gPIPNSSLog
, PR_LOG_DEBUG
, ("[%p] wrote %d bytes\n",
1212 return checkHandshake(bytesWritten
, false, fd
, socketInfo
);
1216 nsSSLIOLayerRead(PRFileDesc
* fd
, void* buf
, int32_t amount
)
1218 return PSMRecv(fd
, buf
, amount
, 0, PR_INTERVAL_NO_TIMEOUT
);
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
)) {
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);
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);
1252 class PrefObserver
: public nsIObserver
{
1256 PrefObserver(nsSSLIOLayerHelpers
* aOwner
) : mOwner(aOwner
) {}
1257 virtual ~PrefObserver() {}
1259 nsSSLIOLayerHelpers
* mOwner
;
1261 } // namespace anonymous
1263 NS_IMPL_THREADSAFE_ISUPPORTS1(PrefObserver
, nsIObserver
)
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")) {
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
);
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
,
1300 if (fd
->identity
== nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity
)
1301 socketInfo
= (nsNSSSocketInfo
*)fd
->secret
;
1303 if ((bytesRead
> 0) && socketInfo
)
1304 socketInfo
->AddPlaintextBytesRead(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");
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
)
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
;
1481 nsSSLIOLayerNewSocket(int32_t family
,
1484 const char *proxyHost
,
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
)) {
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
)
1524 uint32_t contentlen
;
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
) {
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
1545 if (dername
->len
<= 127) {
1546 newitem
.data
= (unsigned char *) PR_Malloc(dername
->len
+ 2);
1547 if (!newitem
.data
) {
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
) {
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
);
1565 /* greater than 256, better be less than 64k */
1566 newitem
.data
= (unsigned char *) PR_Malloc(dername
->len
+ 4);
1567 if (!newitem
.data
) {
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
);
1579 namestring
= CERT_DerNameToAscii(dername
);
1581 /* XXX - keep going until we fail to convert the name */
1582 caNameStrings
[n
] = const_cast<char*>("");
1585 caNameStrings
[n
] = PORT_ArenaStrdup(arena
, namestring
);
1586 PR_Free(namestring
);
1587 if (!caNameStrings
[n
]) {
1593 PR_Free(newitem
.data
);
1600 PR_Free(newitem
.data
);
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
1617 * certCertificateScopeOfUse: struct that represents the decoded extension data
1620 SECItem derConstraint
;
1622 CERTGeneralName
* constraint
; /* decoded constraint */
1623 int port
; /* decoded port number */
1624 } CERTCertificateScopeEntry
;
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
) },
1635 offsetof(CERTCertificateScopeEntry
, derConstraint
) },
1636 { SEC_ASN1_OPTIONAL
| SEC_ASN1_INTEGER
,
1637 offsetof(CERTCertificateScopeEntry
, derPort
) },
1641 static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate
[] = {
1642 { SEC_ASN1_SEQUENCE_OF
, 0, cert_CertificateScopeEntryTemplate
}
1647 * decodes the extension data and create CERTCertificateScopeEntry that can
1648 * be consumed by the code
1651 SECStatus
cert_DecodeScopeOfUseEntries(PRArenaPool
* arena
, SECItem
* extData
,
1652 CERTCertificateScopeEntry
*** entries
,
1655 certCertificateScopeOfUse
* scope
= nullptr;
1656 SECStatus rv
= SECSuccess
;
1659 *entries
= nullptr; /* in case of failure */
1660 *numEntries
= 0; /* ditto */
1662 scope
= (certCertificateScopeOfUse
*)
1663 PORT_ArenaZAlloc(arena
, sizeof(certCertificateScopeOfUse
));
1668 rv
= SEC_ASN1DecodeItem(arena
, (void*)scope
,
1669 cert_CertificateScopeOfUseTemplate
, extData
);
1670 if (rv
!= SECSuccess
) {
1674 *entries
= scope
->entries
;
1675 PR_ASSERT(*entries
);
1677 /* first, let's count 'em. */
1678 for (i
= 0; (*entries
)[i
]; i
++) ;
1681 /* convert certCertificateScopeEntry sequence into what we can readily
1684 for (i
= 0; i
< *numEntries
; i
++) {
1685 (*entries
)[i
]->constraint
=
1686 CERT_DecodeGeneralName(arena
, &((*entries
)[i
]->derConstraint
),
1688 if ((*entries
)[i
]->derPort
.data
) {
1689 (*entries
)[i
]->port
=
1690 (int)DER_GetInteger(&((*entries
)[i
]->derPort
));
1693 (*entries
)[i
]->port
= 0;
1699 if (rv
== SECSuccess
) {
1706 static SECStatus
cert_DecodeCertIPAddress(SECItem
* genname
,
1707 uint32_t* constraint
, uint32_t* mask
)
1709 /* in case of failure */
1713 PR_ASSERT(genname
->data
);
1714 if (!genname
->data
) {
1717 if (genname
->len
!= 8) {
1718 /* the length must be 4 byte IP address with 4 byte subnet mask */
1722 /* get them in the right order */
1723 *constraint
= PR_ntohl((uint32_t)(*genname
->data
));
1724 *mask
= PR_ntohl((uint32_t)(*(genname
->data
+ 4)));
1729 static char* _str_to_lower(char* string
)
1732 return _strlwr(string
);
1735 for (i
= 0; string
[i
] != '\0'; i
++) {
1736 string
[i
] = tolower(string
[i
]);
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 */
1754 PLArenaPool
* arena
= nullptr;
1755 CERTCertificateScopeEntry
** entries
= nullptr;
1756 /* arrays of decoded scope entries */
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
,
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
1775 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
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
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 */
1803 /* this is not a failure: just continue */
1807 switch (genname
->type
) {
1809 /* we have a DNS name constraint; we should use only the host name
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
);
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
1838 /* clean up strings if necessary */
1841 case certIPAddress
: {
1842 uint32_t constraint
;
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
) {
1856 if ((hostIPAddr
& mask
) == (constraint
& mask
)) {
1865 /* ill-formed entry: abort */
1866 continue; /* go to the next entry */
1870 /* we do not need to check the port: go to the next entry */
1874 /* finally, check the optional port number */
1875 if ((entries
[i
]->port
!= 0) && (port
!= entries
[i
]->port
)) {
1876 /* port number does not match */
1881 /* we have a match */
1886 /* clean up entries */
1888 PORT_FreeArena(arena
, false);
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
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;
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
)) {
1927 if (PL_strcmp(mode
, "Select Automatically") == 0) {
1930 else if (PL_strcmp(mode
, "Ask Every Time") == 0) {
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.
1941 nsMemory::Free(mode
);
1946 static bool hasExplicitKeyUsageNonRepudiation(CERTCertificate
*cert
)
1948 /* There is no extension, v1 or v2 certificate */
1949 if (!cert
->extensions
)
1953 SECItem keyUsageItem
;
1954 keyUsageItem
.data
= nullptr;
1956 srv
= CERT_FindKeyUsageExtension(cert
, &keyUsageItem
);
1957 if (srv
== SECFailure
)
1960 unsigned char keyUsage
= keyUsageItem
.data
[0];
1961 PORT_Free (keyUsageItem
.data
);
1963 return !!(keyUsage
& KU_NON_REPUDIATION
);
1966 class ClientAuthDataRunnable
: public SyncRunnableBase
1969 ClientAuthDataRunnable(CERTDistNames
* caNames
,
1970 CERTCertificate
** pRetCert
,
1971 SECKEYPrivateKey
** pRetKey
,
1972 nsNSSSocketInfo
* info
,
1973 CERTCertificate
* serverCert
)
1975 , mErrorCodeToReport(SEC_ERROR_NO_MEMORY
)
1976 , mPRetCert(pRetCert
)
1980 , mServerCert(serverCert
)
1984 SECStatus mRV
; // out
1985 PRErrorCode mErrorCodeToReport
; // out
1986 CERTCertificate
** const mPRetCert
; // in/out
1987 SECKEYPrivateKey
** const mPRetKey
; // in/out
1989 virtual void RunOnTargetThread();
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);
2023 RefPtr
<nsNSSSocketInfo
> info(
2024 reinterpret_cast<nsNSSSocketInfo
*>(socket
->higher
->secret
));
2026 CERTCertificate
* serverCert
= SSL_PeerCertificate(socket
);
2028 NS_NOTREACHED("Missing server certificate should have been detected during "
2029 "server cert authentication.");
2030 PR_SetError(SSL_ERROR_NO_CERTIFICATE
, 0);
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;
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);
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
;
2081 /* create caNameStrings */
2082 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
2087 caNameStrings
= (char**)PORT_ArenaAlloc(arena
,
2088 sizeof(char*)*(mCANames
->nnames
));
2089 if (!caNameStrings
) {
2093 mRV
= nsConvertCANamesToStrings(arena
, caNameStrings
, mCANames
);
2094 if (mRV
!= SECSuccess
) {
2098 /* get the preference */
2099 if (NS_FAILED(nsGetUserCertChoice(&certChoice
))) {
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,
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
) {
2122 /* make sure the list is not empty */
2123 node
= CERT_LIST_HEAD(certList
);
2124 if (CERT_LIST_END(node
, certList
)) {
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
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
);
2143 privKey
= PK11_FindKeyByAnyCert(node
->cert
, wincx
);
2145 if (hasExplicitKeyUsageNonRepudiation(node
->cert
)) {
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
);
2152 // this is a good cert to present
2153 cert
= CERT_DupCertificate(node
->cert
);
2157 keyError
= PR_GetError();
2158 if (keyError
== SEC_ERROR_BAD_PASSWORD
) {
2159 /* problem with password: bail */
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
);
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
;
2188 rv
= cars
->HasRememberedDecision(hostname
, mServerCert
,
2189 rememberedDBKey
, &found
);
2190 if (NS_SUCCEEDED(rv
) && found
) {
2191 hasRemembered
= true;
2195 bool canceled
= false;
2199 if (rememberedDBKey
.IsEmpty())
2205 nsCOMPtr
<nsIX509CertDB
> certdb
;
2206 certdb
= do_GetService(NS_X509CERTDB_CONTRACTID
);
2209 nsCOMPtr
<nsIX509Cert
> found_cert
;
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());
2216 cert
= obj_cert
->GetCert();
2219 nsAutoString nick
, nickWithSerial
, details
;
2220 if (NS_SUCCEEDED(obj_cert
->FormatUIStrings(nick
,
2223 NS_LossyConvertUTF16toASCII
asc(nickWithSerial
);
2224 fprintf(stderr
, "====> remembered serial %s\n", asc
.get());
2232 hasRemembered
= false;
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,
2255 if (mCANames
->nnames
!= 0) {
2256 /* filter the list to those issued by CAs supported by the
2259 mRV
= CERT_FilterCertListByCANames(certList
, mCANames
->nnames
,
2261 certUsageSSLClient
);
2262 if (mRV
!= SECSuccess
) {
2267 if (CERT_LIST_END(CERT_LIST_HEAD(certList
), certList
)) {
2268 /* list is empty - no matching certs */
2272 /* filter it further for hostname restriction */
2273 node
= CERT_LIST_HEAD(certList
);
2274 while (!CERT_LIST_END(node
, certList
)) {
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
);
2284 node
= CERT_LIST_NEXT(node
);
2287 node
= CERT_LIST_NEXT(node
);
2289 if (CERT_LIST_END(CERT_LIST_HEAD(certList
), certList
)) {
2293 nicknames
= getNSSCertNicknamesFromCertList(certList
);
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
);
2304 voidCleaner
ccnCleaner(v
);
2305 NS_ConvertUTF8toUTF16
cn(ccn
);
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
);
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
)
2335 certDetailsList
= (PRUnichar
**)nsMemory::Alloc(sizeof(PRUnichar
*) * nicknames
->numnicknames
);
2336 if (!certDetailsList
) {
2337 nsMemory::Free(certNicknameList
);
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
));
2352 NS_ConvertUTF8toUTF16
i_nickname(nicknames
->nicknames
[CertsToUse
]);
2353 nsAutoString nickWithSerial
, details
;
2355 if (NS_FAILED(tempCert
->FormatUIStrings(i_nickname
, nickWithSerial
, details
)))
2358 certNicknameList
[CertsToUse
] = ToNewUnicode(nickWithSerial
);
2359 if (!certNicknameList
[CertsToUse
])
2361 certDetailsList
[CertsToUse
] = ToNewUnicode(details
);
2362 if (!certDetailsList
[CertsToUse
]) {
2363 nsMemory::Free(certNicknameList
[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
);
2382 nsPSMUITracker tracker
;
2383 if (tracker
.isUIForbidden()) {
2384 rv
= NS_ERROR_NOT_AVAILABLE
;
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
);
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
);
2417 if (cars
&& wantRemember
) {
2418 cars
->RememberDecision(hostname
, mServerCert
,
2419 canceled
? nullptr : cert
.get());
2423 if (canceled
) { rv
= NS_ERROR_NOT_AVAILABLE
; goto loser
; }
2429 /* go get the private key */
2430 privKey
= PK11_FindKeyByAnyCert(cert
, wincx
);
2432 keyError
= PR_GetError();
2433 if (keyError
== SEC_ERROR_BAD_PASSWORD
) {
2434 /* problem with password: bail */
2446 if (mRV
== SECSuccess
) {
2450 int error
= PR_GetError();
2456 PORT_FreeArena(arena
, false);
2459 *mPRetCert
= cert
.forget();
2460 *mPRetKey
= privKey
.forget();
2462 if (mRV
== SECFailure
) {
2463 mErrorCodeToReport
= error
;
2468 nsSSLIOLayerImportFD(PRFileDesc
*fd
,
2469 nsNSSSocketInfo
*infoObject
,
2472 nsNSSShutDownPreventionLock locker
;
2473 PRFileDesc
* sslSock
= SSL_ImportFD(nullptr, fd
);
2475 NS_ASSERTION(false, "NSS: Error importing socket");
2478 SSL_SetPKCS11PinArg(sslSock
, (nsIInterfaceRequestor
*)infoObject
);
2479 SSL_HandshakeCallback(sslSock
, HandshakeCallback
, infoObject
);
2481 // Disable this hook if we connect anonymously. See bug 466080.
2483 infoObject
->GetProviderFlags(&flags
);
2484 if (flags
& nsISocketProvider::ANONYMOUS_CONNECT
) {
2485 SSL_GetClientAuthDataHook(sslSock
, nullptr, infoObject
);
2487 SSL_GetClientAuthDataHook(sslSock
,
2488 (SSLGetClientAuthData
)nsNSS_SSLGetClientAuthData
,
2491 if (SECSuccess
!= SSL_AuthCertificateHook(sslSock
, AuthCertificateHook
,
2493 NS_NOTREACHED("failed to configure AuthCertificateHook");
2497 if (SECSuccess
!= SSL_SetURL(sslSock
, host
)) {
2498 NS_NOTREACHED("SSL_SetURL failed");
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();
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
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.
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
);
2587 peerId
.AppendInt(port
);
2588 if (SECSuccess
!= SSL_SetSockPeerID(fd
, peerId
.get())) {
2589 return NS_ERROR_FAILURE
;
2596 nsSSLIOLayerAddToSocket(int32_t family
,
2599 const char* proxyHost
,
2604 uint32_t providerFlags
)
2606 nsNSSShutDownPreventionLock locker
;
2607 PRFileDesc
* layer
= nullptr;
2608 PRFileDesc
* plaintextLayer
= nullptr;
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
);
2637 NS_ASSERTION(false, "NSS: Error importing socket");
2641 infoObject
->SetFileDescPtr(sslSock
);
2643 rv
= nsSSLIOLayerSetOptions(sslSock
, forSTARTTLS
, proxyHost
, host
, port
,
2649 /* Now, layer ourselves on top of the SSL socket... */
2650 layer
= PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity
,
2651 &nsSSLIOLayerHelpers::nsSSLIOLayerMethods
);
2655 layer
->secret
= (PRFilePrivate
*) infoObject
;
2656 stat
= PR_PushIOLayer(sslSock
, PR_GetLayersIdentity(sslSock
), layer
);
2658 if (stat
== PR_FAILURE
) {
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();
2676 NS_IF_RELEASE(infoObject
);
2680 if (plaintextLayer
) {
2681 PR_PopIOLayer(fd
, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity
);
2682 plaintextLayer
->dtor(plaintextLayer
);
2684 return NS_ERROR_FAILURE
;