Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsNSSIOLayer.h"
9 #include "pkix/pkixtypes.h"
10 #include "nsNSSComponent.h"
11 #include "mozilla/Casting.h"
12 #include "mozilla/DebugOnly.h"
13 #include "mozilla/Telemetry.h"
15 #include "prlog.h"
16 #include "prnetdb.h"
17 #include "nsIPrefService.h"
18 #include "nsIClientAuthDialogs.h"
19 #include "nsClientAuthRemember.h"
20 #include "nsISSLErrorListener.h"
22 #include "nsNetUtil.h"
23 #include "nsPrintfCString.h"
24 #include "SSLServerCertVerification.h"
25 #include "nsNSSCertHelper.h"
26 #include "nsNSSCleaner.h"
28 #ifndef MOZ_NO_EV_CERTS
29 #include "nsIDocShell.h"
30 #include "nsIDocShellTreeItem.h"
31 #include "nsISecureBrowserUI.h"
32 #include "nsIInterfaceRequestorUtils.h"
33 #endif
35 #include "nsCharSeparatedTokenizer.h"
36 #include "nsIConsoleService.h"
37 #include "PSMRunnable.h"
38 #include "ScopedNSSTypes.h"
39 #include "SharedSSLState.h"
40 #include "mozilla/Preferences.h"
41 #include "nsContentUtils.h"
43 #include "ssl.h"
44 #include "sslproto.h"
45 #include "secerr.h"
46 #include "sslerr.h"
47 #include "secder.h"
48 #include "keyhi.h"
50 #include <algorithm>
52 using namespace mozilla;
53 using namespace mozilla::psm;
55 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
56 //reports when doing SSL read/write
58 //#define DUMP_BUFFER //Enable this define along with
59 //DEBUG_SSL_VERBOSE to dump SSL
60 //read/write buffer to a log.
61 //Uses PR_LOG except on Mac where
62 //we always write out to our own
63 //file.
65 namespace {
67 NSSCleanupAutoPtrClass(void, PR_FREEIF)
69 void
70 getSiteKey(const nsACString& hostName, uint16_t port,
71 /*out*/ nsCSubstring& key)
72 {
73 key = hostName;
74 key.AppendASCII(":");
75 key.AppendInt(port);
76 }
78 // SSM_UserCertChoice: enum for cert choice info
79 typedef enum {ASK, AUTO} SSM_UserCertChoice;
81 // Forward secrecy provides us with a proof of posession of the private key
82 // from the server. Without of proof of posession of the private key of the
83 // server, any MitM can force us to false start in a connection that the real
84 // server never participates in, since with RSA key exchange a MitM can
85 // complete the server's first round of the handshake without knowing the
86 // server's public key This would be used, for example, to greatly accelerate
87 // the attacks on RC4 or other attacks that allow a MitM to decrypt encrypted
88 // data without having the server's private key. Without false start, such
89 // attacks are naturally rate limited by network latency and may also be rate
90 // limited explicitly by the server's DoS or other security mechanisms.
91 // Further, because the server that has the private key must participate in the
92 // handshake, the server could detect these kinds of attacks if they they are
93 // repeated rapidly and/or frequently, by noticing lots of invalid or
94 // incomplete handshakes.
95 //
96 // With this in mind, when we choose not to require forward secrecy (when the
97 // pref's value is false), then we will still only false start for RSA key
98 // exchange only if the most recent handshake we've previously done used RSA
99 // key exchange. This way, we prevent any (EC)DHE-to-RSA downgrade attacks for
100 // servers that consistently choose (EC)DHE key exchange. In order to prevent
101 // downgrade from ECDHE_*_GCM cipher suites, we need to also consider downgrade
102 // from TLS 1.2 to earlier versions (bug 861310).
103 static const bool FALSE_START_REQUIRE_FORWARD_SECRECY_DEFAULT = true;
105 // XXX(perf bug 940787): We currently require NPN because there is a very
106 // high (perfect so far) correlation between servers that are false-start-
107 // tolerant and servers that support NPN, according to Google. Without this, we
108 // will run into interop issues with a small percentage of servers that stop
109 // responding when we attempt to false start.
110 static const bool FALSE_START_REQUIRE_NPN_DEFAULT = true;
112 } // unnamed namespace
114 #ifdef PR_LOGGING
115 extern PRLogModuleInfo* gPIPNSSLog;
116 #endif
118 nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags)
119 : mFd(nullptr),
120 mCertVerificationState(before_cert_verification),
121 mSharedState(aState),
122 mForSTARTTLS(false),
123 mHandshakePending(true),
124 mRememberClientAuthCertificate(false),
125 mPreliminaryHandshakeDone(false),
126 mNPNCompleted(false),
127 mFalseStartCallbackCalled(false),
128 mFalseStarted(false),
129 mIsFullHandshake(false),
130 mHandshakeCompleted(false),
131 mJoined(false),
132 mSentClientCert(false),
133 mNotedTimeUntilReady(false),
134 mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
135 mKEAExpected(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
136 mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN),
137 mProviderFlags(providerFlags),
138 mSocketCreationTimestamp(TimeStamp::Now()),
139 mPlaintextBytesRead(0)
140 {
141 mTLSVersionRange.min = 0;
142 mTLSVersionRange.max = 0;
143 }
145 NS_IMPL_ISUPPORTS_INHERITED(nsNSSSocketInfo, TransportSecurityInfo,
146 nsISSLSocketControl,
147 nsIClientAuthUserDecision)
149 NS_IMETHODIMP
150 nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags)
151 {
152 *aProviderFlags = mProviderFlags;
153 return NS_OK;
154 }
156 NS_IMETHODIMP
157 nsNSSSocketInfo::GetKEAUsed(int16_t* aKea)
158 {
159 *aKea = mKEAUsed;
160 return NS_OK;
161 }
163 NS_IMETHODIMP
164 nsNSSSocketInfo::GetKEAExpected(int16_t* aKea)
165 {
166 *aKea = mKEAExpected;
167 return NS_OK;
168 }
170 NS_IMETHODIMP
171 nsNSSSocketInfo::SetKEAExpected(int16_t aKea)
172 {
173 mKEAExpected = aKea;
174 return NS_OK;
175 }
177 NS_IMETHODIMP
178 nsNSSSocketInfo::GetSSLVersionUsed(int16_t* aSSLVersionUsed)
179 {
180 *aSSLVersionUsed = mSSLVersionUsed;
181 return NS_OK;
182 }
184 NS_IMETHODIMP
185 nsNSSSocketInfo::GetRememberClientAuthCertificate(bool* aRemember)
186 {
187 NS_ENSURE_ARG_POINTER(aRemember);
188 *aRemember = mRememberClientAuthCertificate;
189 return NS_OK;
190 }
192 NS_IMETHODIMP
193 nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRemember)
194 {
195 mRememberClientAuthCertificate = aRemember;
196 return NS_OK;
197 }
199 NS_IMETHODIMP
200 nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
201 {
202 *aCallbacks = mCallbacks;
203 NS_IF_ADDREF(*aCallbacks);
204 return NS_OK;
205 }
207 NS_IMETHODIMP
208 nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
209 {
210 if (!aCallbacks) {
211 mCallbacks = nullptr;
212 return NS_OK;
213 }
215 mCallbacks = aCallbacks;
217 return NS_OK;
218 }
220 #ifndef MOZ_NO_EV_CERTS
221 static void
222 getSecureBrowserUI(nsIInterfaceRequestor* callbacks,
223 nsISecureBrowserUI** result)
224 {
225 NS_ASSERTION(result, "result parameter to getSecureBrowserUI is null");
226 *result = nullptr;
228 NS_ASSERTION(NS_IsMainThread(),
229 "getSecureBrowserUI called off the main thread");
231 if (!callbacks)
232 return;
234 nsCOMPtr<nsISecureBrowserUI> secureUI = do_GetInterface(callbacks);
235 if (secureUI) {
236 secureUI.forget(result);
237 return;
238 }
240 nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(callbacks);
241 if (item) {
242 nsCOMPtr<nsIDocShellTreeItem> rootItem;
243 (void) item->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
245 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(rootItem);
246 if (docShell) {
247 (void) docShell->GetSecurityUI(result);
248 }
249 }
250 }
251 #endif
253 void
254 nsNSSSocketInfo::NoteTimeUntilReady()
255 {
256 if (mNotedTimeUntilReady)
257 return;
259 mNotedTimeUntilReady = true;
261 // This will include TCP and proxy tunnel wait time
262 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
263 mSocketCreationTimestamp, TimeStamp::Now());
264 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
265 ("[%p] nsNSSSocketInfo::NoteTimeUntilReady\n", mFd));
266 }
268 void
269 nsNSSSocketInfo::SetHandshakeCompleted()
270 {
271 if (!mHandshakeCompleted) {
272 enum HandshakeType {
273 Resumption = 1,
274 FalseStarted = 2,
275 ChoseNotToFalseStart = 3,
276 NotAllowedToFalseStart = 4,
277 };
279 HandshakeType handshakeType = !IsFullHandshake() ? Resumption
280 : mFalseStarted ? FalseStarted
281 : mFalseStartCallbackCalled ? ChoseNotToFalseStart
282 : NotAllowedToFalseStart;
284 // This will include TCP and proxy tunnel wait time
285 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_HANDSHAKE_FINISHED,
286 mSocketCreationTimestamp, TimeStamp::Now());
288 // If the handshake is completed for the first time from just 1 callback
289 // that means that TLS session resumption must have been used.
290 Telemetry::Accumulate(Telemetry::SSL_RESUMED_SESSION,
291 handshakeType == Resumption);
292 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_TYPE, handshakeType);
293 }
296 // Remove the plain text layer as it is not needed anymore.
297 // The plain text layer is not always present - so its not a fatal error
298 // if it cannot be removed
299 PRFileDesc* poppedPlaintext =
300 PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
301 if (poppedPlaintext) {
302 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
303 poppedPlaintext->dtor(poppedPlaintext);
304 }
306 mHandshakeCompleted = true;
308 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
309 ("[%p] nsNSSSocketInfo::SetHandshakeCompleted\n", (void*) mFd));
311 mIsFullHandshake = false; // reset for next handshake on this connection
312 }
314 void
315 nsNSSSocketInfo::SetNegotiatedNPN(const char* value, uint32_t length)
316 {
317 if (!value) {
318 mNegotiatedNPN.Truncate();
319 } else {
320 mNegotiatedNPN.Assign(value, length);
321 }
322 mNPNCompleted = true;
323 }
325 NS_IMETHODIMP
326 nsNSSSocketInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN)
327 {
328 if (!mNPNCompleted)
329 return NS_ERROR_NOT_CONNECTED;
331 aNegotiatedNPN = mNegotiatedNPN;
332 return NS_OK;
333 }
335 NS_IMETHODIMP
336 nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
337 const nsACString& hostname,
338 int32_t port,
339 bool* _retval)
340 {
341 *_retval = false;
343 // Different ports may not be joined together
344 if (port != GetPort())
345 return NS_OK;
347 // Make sure NPN has been completed and matches requested npnProtocol
348 if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
349 return NS_OK;
351 // If this is the same hostname then the certicate status does not
352 // need to be considered. They are joinable.
353 if (hostname.Equals(GetHostName())) {
354 *_retval = true;
355 return NS_OK;
356 }
358 // Before checking the server certificate we need to make sure the
359 // handshake has completed.
360 if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
361 return NS_OK;
363 // If the cert has error bits (e.g. it is untrusted) then do not join.
364 // The value of mHaveCertErrorBits is only reliable because we know that
365 // the handshake completed.
366 if (SSLStatus()->mHaveCertErrorBits)
367 return NS_OK;
369 // If the connection is using client certificates then do not join
370 // because the user decides on whether to send client certs to hosts on a
371 // per-domain basis.
372 if (mSentClientCert)
373 return NS_OK;
375 // Ensure that the server certificate covers the hostname that would
376 // like to join this connection
378 ScopedCERTCertificate nssCert;
380 nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
381 if (cert2)
382 nssCert = cert2->GetCert();
384 if (!nssCert)
385 return NS_OK;
387 if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
388 SECSuccess)
389 return NS_OK;
391 // All tests pass - this is joinable
392 mJoined = true;
393 *_retval = true;
394 return NS_OK;
395 }
397 bool
398 nsNSSSocketInfo::GetForSTARTTLS()
399 {
400 return mForSTARTTLS;
401 }
403 void
404 nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
405 {
406 mForSTARTTLS = aForSTARTTLS;
407 }
409 NS_IMETHODIMP
410 nsNSSSocketInfo::ProxyStartSSL()
411 {
412 return ActivateSSL();
413 }
415 NS_IMETHODIMP
416 nsNSSSocketInfo::StartTLS()
417 {
418 return ActivateSSL();
419 }
421 NS_IMETHODIMP
422 nsNSSSocketInfo::SetNPNList(nsTArray<nsCString>& protocolArray)
423 {
424 nsNSSShutDownPreventionLock locker;
425 if (isAlreadyShutDown())
426 return NS_ERROR_NOT_AVAILABLE;
427 if (!mFd)
428 return NS_ERROR_FAILURE;
430 // the npn list is a concatenated list of 8 bit byte strings.
431 nsCString npnList;
433 for (uint32_t index = 0; index < protocolArray.Length(); ++index) {
434 if (protocolArray[index].IsEmpty() ||
435 protocolArray[index].Length() > 255)
436 return NS_ERROR_ILLEGAL_VALUE;
438 npnList.Append(protocolArray[index].Length());
439 npnList.Append(protocolArray[index]);
440 }
442 if (SSL_SetNextProtoNego(
443 mFd,
444 reinterpret_cast<const unsigned char*>(npnList.get()),
445 npnList.Length()) != SECSuccess)
446 return NS_ERROR_FAILURE;
448 return NS_OK;
449 }
451 nsresult
452 nsNSSSocketInfo::ActivateSSL()
453 {
454 nsNSSShutDownPreventionLock locker;
455 if (isAlreadyShutDown())
456 return NS_ERROR_NOT_AVAILABLE;
458 if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
459 return NS_ERROR_FAILURE;
460 if (SECSuccess != SSL_ResetHandshake(mFd, false))
461 return NS_ERROR_FAILURE;
463 mHandshakePending = true;
465 return NS_OK;
466 }
468 nsresult
469 nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
470 {
471 *aFilePtr = mFd;
472 return NS_OK;
473 }
475 nsresult
476 nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
477 {
478 mFd = aFilePtr;
479 return NS_OK;
480 }
482 #ifndef MOZ_NO_EV_CERTS
483 class PreviousCertRunnable : public SyncRunnableBase
484 {
485 public:
486 PreviousCertRunnable(nsIInterfaceRequestor* callbacks)
487 : mCallbacks(callbacks)
488 {
489 }
491 virtual void RunOnTargetThread()
492 {
493 nsCOMPtr<nsISecureBrowserUI> secureUI;
494 getSecureBrowserUI(mCallbacks, getter_AddRefs(secureUI));
495 nsCOMPtr<nsISSLStatusProvider> statusProvider = do_QueryInterface(secureUI);
496 if (statusProvider) {
497 nsCOMPtr<nsISSLStatus> status;
498 (void) statusProvider->GetSSLStatus(getter_AddRefs(status));
499 if (status) {
500 (void) status->GetServerCert(getter_AddRefs(mPreviousCert));
501 }
502 }
503 }
505 nsCOMPtr<nsIX509Cert> mPreviousCert; // out
506 private:
507 nsCOMPtr<nsIInterfaceRequestor> mCallbacks; // in
508 };
509 #endif
511 void
512 nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
513 {
514 NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
515 *_result = nullptr;
517 #ifndef MOZ_NO_EV_CERTS
518 RefPtr<PreviousCertRunnable> runnable(new PreviousCertRunnable(mCallbacks));
519 DebugOnly<nsresult> rv = runnable->DispatchToMainThreadAndWait();
520 NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
521 runnable->mPreviousCert.forget(_result);
522 #endif
523 }
525 void
526 nsNSSSocketInfo::SetCertVerificationWaiting()
527 {
528 // mCertVerificationState may be before_cert_verification for the first
529 // handshake on the connection, or after_cert_verification for subsequent
530 // renegotiation handshakes.
531 NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
532 "Invalid state transition to waiting_for_cert_verification");
533 mCertVerificationState = waiting_for_cert_verification;
534 }
536 // Be careful that SetCertVerificationResult does NOT get called while we are
537 // processing a SSL callback function, because SSL_AuthCertificateComplete will
538 // attempt to acquire locks that are already held by libssl when it calls
539 // callbacks.
540 void
541 nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
542 SSLErrorMessageType errorMessageType)
543 {
544 NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
545 "Invalid state transition to cert_verification_finished");
547 if (mFd) {
548 SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
549 // Only replace errorCode if there was originally no error
550 if (rv != SECSuccess && errorCode == 0) {
551 errorCode = PR_GetError();
552 errorMessageType = PlainErrorMessage;
553 if (errorCode == 0) {
554 NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
555 errorCode = PR_INVALID_STATE_ERROR;
556 }
557 }
558 }
560 if (errorCode) {
561 SetCanceled(errorCode, errorMessageType);
562 }
564 if (mPlaintextBytesRead && !errorCode) {
565 Telemetry::Accumulate(Telemetry::SSL_BYTES_BEFORE_CERT_CALLBACK,
566 SafeCast<uint32_t>(mPlaintextBytesRead));
567 }
569 mCertVerificationState = after_cert_verification;
570 }
572 SharedSSLState&
573 nsNSSSocketInfo::SharedState()
574 {
575 return mSharedState;
576 }
578 void nsSSLIOLayerHelpers::Cleanup()
579 {
580 mTLSIntoleranceInfo.Clear();
582 if (mRenegoUnrestrictedSites) {
583 delete mRenegoUnrestrictedSites;
584 mRenegoUnrestrictedSites = nullptr;
585 }
586 }
588 static void
589 nsHandleSSLError(nsNSSSocketInfo* socketInfo,
590 ::mozilla::psm::SSLErrorMessageType errtype,
591 PRErrorCode err)
592 {
593 if (!NS_IsMainThread()) {
594 NS_ERROR("nsHandleSSLError called off the main thread");
595 return;
596 }
598 // SetCanceled is only called by the main thread or the socket transport
599 // thread. Whenever this function is called on the main thread, the SSL
600 // thread is blocked on it. So, no mutex is necessary for
601 // SetCanceled()/GetError*().
602 if (socketInfo->GetErrorCode()) {
603 // If the socket has been flagged as canceled,
604 // the code who did was responsible for setting the error code.
605 return;
606 }
608 nsresult rv;
609 NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
610 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
611 if (NS_FAILED(rv))
612 return;
614 // Try to get a nsISSLErrorListener implementation from the socket consumer.
615 nsCOMPtr<nsIInterfaceRequestor> cb;
616 socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
617 if (cb) {
618 nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(cb);
619 if (sel) {
620 nsIInterfaceRequestor* csi = static_cast<nsIInterfaceRequestor*>(socketInfo);
622 nsCString hostWithPortString;
623 getSiteKey(socketInfo->GetHostName(), socketInfo->GetPort(),
624 hostWithPortString);
626 bool suppressMessage = false; // obsolete, ignored
627 rv = sel->NotifySSLError(csi, err, hostWithPortString, &suppressMessage);
628 }
629 }
631 // We must cancel first, which sets the error code.
632 socketInfo->SetCanceled(err, PlainErrorMessage);
633 nsXPIDLString errorString;
634 socketInfo->GetErrorLogMessage(err, errtype, errorString);
636 if (!errorString.IsEmpty()) {
637 nsContentUtils::LogSimpleConsoleError(errorString, "SSL");
638 }
639 }
641 namespace {
643 enum Operation { reading, writing, not_reading_or_writing };
645 int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
646 PRFileDesc* ssl_layer_fd,
647 nsNSSSocketInfo* socketInfo);
649 nsNSSSocketInfo*
650 getSocketInfoIfRunning(PRFileDesc* fd, Operation op,
651 const nsNSSShutDownPreventionLock& /*proofOfLock*/)
652 {
653 if (!fd || !fd->lower || !fd->secret ||
654 fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
655 NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
656 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
657 return nullptr;
658 }
660 nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*) fd->secret;
662 if (socketInfo->isAlreadyShutDown() || socketInfo->isPK11LoggedOut()) {
663 PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
664 return nullptr;
665 }
667 if (socketInfo->GetErrorCode()) {
668 PRErrorCode err = socketInfo->GetErrorCode();
669 PR_SetError(err, 0);
670 if (op == reading || op == writing) {
671 // We must do TLS intolerance checks for reads and writes, for timeouts
672 // in particular.
673 (void) checkHandshake(-1, op == reading, fd, socketInfo);
674 }
676 // If we get here, it is probably because cert verification failed and this
677 // is the first I/O attempt since that failure.
678 return nullptr;
679 }
681 return socketInfo;
682 }
684 } // unnnamed namespace
686 static PRStatus
687 nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
688 PRIntervalTime timeout)
689 {
690 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n",
691 (void*) fd));
692 nsNSSShutDownPreventionLock locker;
693 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
694 return PR_FAILURE;
696 PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
697 if (status != PR_SUCCESS) {
698 PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
699 (void*) fd, PR_GetError()));
700 return status;
701 }
703 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*) fd));
704 return status;
705 }
707 void
708 nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName,
709 int16_t port, uint16_t tolerant)
710 {
711 nsCString key;
712 getSiteKey(hostName, port, key);
714 MutexAutoLock lock(mutex);
716 IntoleranceEntry entry;
717 if (mTLSIntoleranceInfo.Get(key, &entry)) {
718 entry.AssertInvariant();
719 entry.tolerant = std::max(entry.tolerant, tolerant);
720 if (entry.intolerant != 0 && entry.intolerant <= entry.tolerant) {
721 entry.intolerant = entry.tolerant + 1;
722 }
723 } else {
724 entry.tolerant = tolerant;
725 entry.intolerant = 0;
726 }
728 entry.AssertInvariant();
730 mTLSIntoleranceInfo.Put(key, entry);
731 }
733 // returns true if we should retry the handshake
734 bool
735 nsSSLIOLayerHelpers::rememberIntolerantAtVersion(const nsACString& hostName,
736 int16_t port,
737 uint16_t minVersion,
738 uint16_t intolerant)
739 {
740 nsCString key;
741 getSiteKey(hostName, port, key);
743 MutexAutoLock lock(mutex);
745 if (intolerant <= minVersion) {
746 // We can't fall back any further. Assume that intolerance isn't the issue.
747 IntoleranceEntry entry;
748 if (mTLSIntoleranceInfo.Get(key, &entry)) {
749 entry.AssertInvariant();
750 entry.intolerant = 0;
751 entry.AssertInvariant();
752 mTLSIntoleranceInfo.Put(key, entry);
753 }
755 return false;
756 }
758 IntoleranceEntry entry;
759 if (mTLSIntoleranceInfo.Get(key, &entry)) {
760 entry.AssertInvariant();
761 if (intolerant <= entry.tolerant) {
762 // We already know the server is tolerant at an equal or higher version.
763 return false;
764 }
765 if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
766 // We already know that the server is intolerant at a lower version.
767 return true;
768 }
769 } else {
770 entry.tolerant = 0;
771 }
773 entry.intolerant = intolerant;
774 entry.AssertInvariant();
775 mTLSIntoleranceInfo.Put(key, entry);
777 return true;
778 }
780 void
781 nsSSLIOLayerHelpers::adjustForTLSIntolerance(const nsACString& hostName,
782 int16_t port,
783 /*in/out*/ SSLVersionRange& range)
784 {
785 IntoleranceEntry entry;
787 {
788 nsCString key;
789 getSiteKey(hostName, port, key);
791 MutexAutoLock lock(mutex);
792 if (!mTLSIntoleranceInfo.Get(key, &entry)) {
793 return;
794 }
795 }
797 entry.AssertInvariant();
799 if (entry.intolerant != 0) {
800 // We've tried connecting at a higher range but failed, so try at the
801 // version we haven't tried yet, unless we have reached the minimum.
802 if (range.min < entry.intolerant) {
803 range.max = entry.intolerant - 1;
804 }
805 }
806 }
808 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
809 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
810 PRDescIdentity nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity;
811 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
812 PRIOMethods nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods;
814 static PRStatus
815 nsSSLIOLayerClose(PRFileDesc* fd)
816 {
817 nsNSSShutDownPreventionLock locker;
818 if (!fd)
819 return PR_FAILURE;
821 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n",
822 (void*) fd));
824 nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*) fd->secret;
825 NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
827 return socketInfo->CloseSocketAndDestroy(locker);
828 }
830 PRStatus
831 nsNSSSocketInfo::CloseSocketAndDestroy(
832 const nsNSSShutDownPreventionLock& /*proofOfLock*/)
833 {
834 nsNSSShutDownList::trackSSLSocketClose();
836 PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
837 NS_ASSERTION(popped &&
838 popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
839 "SSL Layer not on top of stack");
841 // The plain text layer is not always present - so its not a fatal error
842 // if it cannot be removed
843 PRFileDesc* poppedPlaintext =
844 PR_GetIdentitiesLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
845 if (poppedPlaintext) {
846 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
847 poppedPlaintext->dtor(poppedPlaintext);
848 }
850 PRStatus status = mFd->methods->close(mFd);
852 // the nsNSSSocketInfo instance can out-live the connection, so we need some
853 // indication that the connection has been closed. mFd == nullptr is that
854 // indication. This is needed, for example, when the connection is closed
855 // before we have finished validating the server's certificate.
856 mFd = nullptr;
858 if (status != PR_SUCCESS) return status;
860 popped->identity = PR_INVALID_IO_LAYER;
861 NS_RELEASE_THIS();
862 popped->dtor(popped);
864 return PR_SUCCESS;
865 }
867 #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
868 // Dumps a (potentially binary) buffer using SSM_DEBUG. (We could have used
869 // the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)
870 #define DUMPBUF_LINESIZE 24
871 static void
872 nsDumpBuffer(unsigned char* buf, int len)
873 {
874 char hexbuf[DUMPBUF_LINESIZE*3+1];
875 char chrbuf[DUMPBUF_LINESIZE+1];
876 static const char* hex = "0123456789abcdef";
877 int i = 0;
878 int l = 0;
879 char ch;
880 char* c;
881 char* h;
882 if (len == 0)
883 return;
884 hexbuf[DUMPBUF_LINESIZE*3] = '\0';
885 chrbuf[DUMPBUF_LINESIZE] = '\0';
886 (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
887 (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
888 h = hexbuf;
889 c = chrbuf;
891 while (i < len) {
892 ch = buf[i];
894 if (l == DUMPBUF_LINESIZE) {
895 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
896 (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
897 (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
898 h = hexbuf;
899 c = chrbuf;
900 l = 0;
901 }
903 // Convert a character to hex.
904 *h++ = hex[(ch >> 4) & 0xf];
905 *h++ = hex[ch & 0xf];
906 h++;
908 // Put the character (if it's printable) into the character buffer.
909 if ((ch >= 0x20) && (ch <= 0x7e)) {
910 *c++ = ch;
911 } else {
912 *c++ = '.';
913 }
914 i++; l++;
915 }
916 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
917 }
919 #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
920 #else
921 #define DEBUG_DUMP_BUFFER(buf,len)
922 #endif
924 class SSLErrorRunnable : public SyncRunnableBase
925 {
926 public:
927 SSLErrorRunnable(nsNSSSocketInfo* infoObject,
928 ::mozilla::psm::SSLErrorMessageType errtype,
929 PRErrorCode errorCode)
930 : mInfoObject(infoObject)
931 , mErrType(errtype)
932 , mErrorCode(errorCode)
933 {
934 }
936 virtual void RunOnTargetThread()
937 {
938 nsHandleSSLError(mInfoObject, mErrType, mErrorCode);
939 }
941 RefPtr<nsNSSSocketInfo> mInfoObject;
942 ::mozilla::psm::SSLErrorMessageType mErrType;
943 const PRErrorCode mErrorCode;
944 };
946 namespace {
948 bool
949 retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
950 {
951 // This function is supposed to decide which error codes should
952 // be used to conclude server is TLS intolerant.
953 // Note this only happens during the initial SSL handshake.
955 SSLVersionRange range = socketInfo->GetTLSVersionRange();
957 uint32_t reason;
958 switch (err) {
959 case SSL_ERROR_BAD_MAC_ALERT: reason = 1; break;
960 case SSL_ERROR_BAD_MAC_READ: reason = 2; break;
961 case SSL_ERROR_HANDSHAKE_FAILURE_ALERT: reason = 3; break;
962 case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT: reason = 4; break;
963 case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE: reason = 5; break;
964 case SSL_ERROR_ILLEGAL_PARAMETER_ALERT: reason = 6; break;
965 case SSL_ERROR_NO_CYPHER_OVERLAP: reason = 7; break;
966 case SSL_ERROR_BAD_SERVER: reason = 8; break;
967 case SSL_ERROR_BAD_BLOCK_PADDING: reason = 9; break;
968 case SSL_ERROR_UNSUPPORTED_VERSION: reason = 10; break;
969 case SSL_ERROR_PROTOCOL_VERSION_ALERT: reason = 11; break;
970 case SSL_ERROR_RX_MALFORMED_FINISHED: reason = 12; break;
971 case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE: reason = 13; break;
972 case SSL_ERROR_DECODE_ERROR_ALERT: reason = 14; break;
973 case SSL_ERROR_RX_UNKNOWN_ALERT: reason = 15; break;
975 case PR_CONNECT_RESET_ERROR: reason = 16; goto conditional;
976 case PR_END_OF_FILE_ERROR: reason = 17; goto conditional;
978 // When not using a proxy we'll see a connection reset error.
979 // When using a proxy, we'll see an end of file error.
980 // In addition check for some error codes where it is reasonable
981 // to retry without TLS.
983 // Don't allow STARTTLS connections to fall back on connection resets or
984 // EOF. Also, don't fall back from TLS 1.0 to SSL 3.0 for connection
985 // resets, because connection resets have too many false positives,
986 // and we want to maximize how often we send TLS 1.0+ with extensions
987 // if at all reasonable. Unfortunately, it appears we have to allow
988 // fallback from TLS 1.2 and TLS 1.1 for connection resets due to bad
989 // servers and possibly bad intermediaries.
990 conditional:
991 if ((err == PR_CONNECT_RESET_ERROR &&
992 range.max <= SSL_LIBRARY_VERSION_TLS_1_0) ||
993 socketInfo->GetForSTARTTLS()) {
994 return false;
995 }
996 break;
998 default:
999 return false;
1000 }
1002 Telemetry::ID pre;
1003 Telemetry::ID post;
1004 switch (range.max) {
1005 case SSL_LIBRARY_VERSION_TLS_1_2:
1006 pre = Telemetry::SSL_TLS12_INTOLERANCE_REASON_PRE;
1007 post = Telemetry::SSL_TLS12_INTOLERANCE_REASON_POST;
1008 break;
1009 case SSL_LIBRARY_VERSION_TLS_1_1:
1010 pre = Telemetry::SSL_TLS11_INTOLERANCE_REASON_PRE;
1011 post = Telemetry::SSL_TLS11_INTOLERANCE_REASON_POST;
1012 break;
1013 case SSL_LIBRARY_VERSION_TLS_1_0:
1014 pre = Telemetry::SSL_TLS10_INTOLERANCE_REASON_PRE;
1015 post = Telemetry::SSL_TLS10_INTOLERANCE_REASON_POST;
1016 break;
1017 case SSL_LIBRARY_VERSION_3_0:
1018 pre = Telemetry::SSL_SSL30_INTOLERANCE_REASON_PRE;
1019 post = Telemetry::SSL_SSL30_INTOLERANCE_REASON_POST;
1020 break;
1021 default:
1022 MOZ_CRASH("impossible TLS version");
1023 return false;
1024 }
1026 // The difference between _PRE and _POST represents how often we avoided
1027 // TLS intolerance fallback due to remembered tolerance.
1028 Telemetry::Accumulate(pre, reason);
1030 if (!socketInfo->SharedState().IOLayerHelpers()
1031 .rememberIntolerantAtVersion(socketInfo->GetHostName(),
1032 socketInfo->GetPort(),
1033 range.min, range.max)) {
1034 return false;
1035 }
1037 Telemetry::Accumulate(post, reason);
1039 return true;
1040 }
1042 int32_t
1043 checkHandshake(int32_t bytesTransfered, bool wasReading,
1044 PRFileDesc* ssl_layer_fd, nsNSSSocketInfo* socketInfo)
1045 {
1046 const PRErrorCode originalError = PR_GetError();
1047 PRErrorCode err = originalError;
1049 // This is where we work around all of those SSL servers that don't
1050 // conform to the SSL spec and shutdown a connection when we request
1051 // SSL v3.1 (aka TLS). The spec says the client says what version
1052 // of the protocol we're willing to perform, in our case SSL v3.1
1053 // In its response, the server says which version it wants to perform.
1054 // Many servers out there only know how to do v3.0. Next, we're supposed
1055 // to send back the version of the protocol we requested (ie v3.1). At
1056 // this point many servers's implementations are broken and they shut
1057 // down the connection when they don't see the version they sent back.
1058 // This is supposed to prevent a man in the middle from forcing one
1059 // side to dumb down to a lower level of the protocol. Unfortunately,
1060 // there are enough broken servers out there that such a gross work-around
1061 // is necessary. :(
1063 // Do NOT assume TLS intolerance on a closed connection after bad cert ui was shown.
1064 // Simply retry.
1065 // This depends on the fact that Cert UI will not be shown again,
1066 // should the user override the bad cert.
1068 bool handleHandshakeResultNow = socketInfo->IsHandshakePending();
1070 bool wantRetry = false;
1072 if (0 > bytesTransfered) {
1073 if (handleHandshakeResultNow) {
1074 if (PR_WOULD_BLOCK_ERROR == err) {
1075 PR_SetError(err, 0);
1076 return bytesTransfered;
1077 }
1079 wantRetry = retryDueToTLSIntolerance(err, socketInfo);
1080 }
1082 // This is the common place where we trigger non-cert-errors on a SSL
1083 // socket. This might be reached at any time of the connection.
1084 //
1085 // The socketInfo->GetErrorCode() check is here to ensure we don't try to
1086 // do the synchronous dispatch to the main thread unnecessarily after we've
1087 // already handled a certificate error. (SSLErrorRunnable calls
1088 // nsHandleSSLError, which has logic to avoid replacing the error message,
1089 // so without the !socketInfo->GetErrorCode(), it would just be an
1090 // expensive no-op.)
1091 if (!wantRetry && (IS_SSL_ERROR(err) || IS_SEC_ERROR(err)) &&
1092 !socketInfo->GetErrorCode()) {
1093 RefPtr<SyncRunnableBase> runnable(new SSLErrorRunnable(socketInfo,
1094 PlainErrorMessage,
1095 err));
1096 (void) runnable->DispatchToMainThreadAndWait();
1097 }
1098 } else if (wasReading && 0 == bytesTransfered) {
1099 // zero bytes on reading, socket closed
1100 if (handleHandshakeResultNow) {
1101 wantRetry = retryDueToTLSIntolerance(PR_END_OF_FILE_ERROR, socketInfo);
1102 }
1103 }
1105 if (wantRetry) {
1106 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1107 ("[%p] checkHandshake: will retry with lower max TLS version\n",
1108 ssl_layer_fd));
1109 // We want to cause the network layer to retry the connection.
1110 err = PR_CONNECT_RESET_ERROR;
1111 if (wasReading)
1112 bytesTransfered = -1;
1113 }
1115 // TLS intolerant servers only cause the first transfer to fail, so let's
1116 // set the HandshakePending attribute to false so that we don't try the logic
1117 // above again in a subsequent transfer.
1118 if (handleHandshakeResultNow) {
1119 socketInfo->SetHandshakeNotPending();
1120 }
1122 if (bytesTransfered < 0) {
1123 // Remember that we encountered an error so that getSocketInfoIfRunning
1124 // will correctly cause us to fail if another part of Gecko
1125 // (erroneously) calls an I/O function (PR_Send/PR_Recv/etc.) again on
1126 // this socket. Note that we use the original error because if we use
1127 // PR_CONNECT_RESET_ERROR, we'll repeated try to reconnect.
1128 if (originalError != PR_WOULD_BLOCK_ERROR && !socketInfo->GetErrorCode()) {
1129 socketInfo->SetCanceled(originalError, PlainErrorMessage);
1130 }
1131 PR_SetError(err, 0);
1132 }
1134 return bytesTransfered;
1135 }
1137 }
1139 static int16_t
1140 nsSSLIOLayerPoll(PRFileDesc* fd, int16_t in_flags, int16_t* out_flags)
1141 {
1142 nsNSSShutDownPreventionLock locker;
1144 if (!out_flags) {
1145 NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
1146 return 0;
1147 }
1149 *out_flags = 0;
1151 nsNSSSocketInfo* socketInfo =
1152 getSocketInfoIfRunning(fd, not_reading_or_writing, locker);
1154 if (!socketInfo) {
1155 // If we get here, it is probably because certificate validation failed
1156 // and this is the first I/O operation after the failure.
1157 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1158 ("[%p] polling SSL socket right after certificate verification failed "
1159 "or NSS shutdown or SDR logout %d\n",
1160 fd, (int) in_flags));
1162 NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
1163 "caller did not poll for EXCEPT (canceled)");
1164 // Since this poll method cannot return errors, we want the caller to call
1165 // PR_Send/PR_Recv right away to get the error, so we tell that we are
1166 // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
1167 *out_flags = in_flags | PR_POLL_EXCEPT; // see also bug 480619
1168 return in_flags;
1169 }
1171 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1172 (socketInfo->IsWaitingForCertVerification()
1173 ? "[%p] polling SSL socket during certificate verification using lower %d\n"
1174 : "[%p] poll SSL socket using lower %d\n",
1175 fd, (int) in_flags));
1177 // We want the handshake to continue during certificate validation, so we
1178 // don't need to do anything special here. libssl automatically blocks when
1179 // it reaches any point that would be unsafe to send/receive something before
1180 // cert validation is complete.
1181 int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
1182 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
1183 (void*) fd, (int) result));
1184 return result;
1185 }
1187 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers()
1188 : mRenegoUnrestrictedSites(nullptr)
1189 , mTreatUnsafeNegotiationAsBroken(false)
1190 , mWarnLevelMissingRFC5746(1)
1191 , mTLSIntoleranceInfo(16)
1192 , mFalseStartRequireNPN(true)
1193 , mFalseStartRequireForwardSecrecy(false)
1194 , mutex("nsSSLIOLayerHelpers.mutex")
1195 {
1196 }
1198 static int
1199 _PSM_InvalidInt(void)
1200 {
1201 PR_ASSERT(!"I/O method is invalid");
1202 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1203 return -1;
1204 }
1206 static int64_t
1207 _PSM_InvalidInt64(void)
1208 {
1209 PR_ASSERT(!"I/O method is invalid");
1210 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1211 return -1;
1212 }
1214 static PRStatus
1215 _PSM_InvalidStatus(void)
1216 {
1217 PR_ASSERT(!"I/O method is invalid");
1218 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1219 return PR_FAILURE;
1220 }
1222 static PRFileDesc*
1223 _PSM_InvalidDesc(void)
1224 {
1225 PR_ASSERT(!"I/O method is invalid");
1226 PR_SetError(PR_INVALID_METHOD_ERROR, 0);
1227 return nullptr;
1228 }
1230 static PRStatus
1231 PSMGetsockname(PRFileDesc* fd, PRNetAddr* addr)
1232 {
1233 nsNSSShutDownPreventionLock locker;
1234 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1235 return PR_FAILURE;
1237 return fd->lower->methods->getsockname(fd->lower, addr);
1238 }
1240 static PRStatus
1241 PSMGetpeername(PRFileDesc* fd, PRNetAddr* addr)
1242 {
1243 nsNSSShutDownPreventionLock locker;
1244 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1245 return PR_FAILURE;
1247 return fd->lower->methods->getpeername(fd->lower, addr);
1248 }
1250 static PRStatus
1251 PSMGetsocketoption(PRFileDesc* fd, PRSocketOptionData* data)
1252 {
1253 nsNSSShutDownPreventionLock locker;
1254 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1255 return PR_FAILURE;
1257 return fd->lower->methods->getsocketoption(fd, data);
1258 }
1260 static PRStatus
1261 PSMSetsocketoption(PRFileDesc* fd, const PRSocketOptionData* data)
1262 {
1263 nsNSSShutDownPreventionLock locker;
1264 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1265 return PR_FAILURE;
1267 return fd->lower->methods->setsocketoption(fd, data);
1268 }
1270 static int32_t
1271 PSMRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
1272 PRIntervalTime timeout)
1273 {
1274 nsNSSShutDownPreventionLock locker;
1275 nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, reading, locker);
1276 if (!socketInfo)
1277 return -1;
1279 if (flags != PR_MSG_PEEK && flags != 0) {
1280 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1281 return -1;
1282 }
1284 int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
1285 timeout);
1287 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] read %d bytes\n", (void*) fd,
1288 bytesRead));
1290 #ifdef DEBUG_SSL_VERBOSE
1291 DEBUG_DUMP_BUFFER((unsigned char*) buf, bytesRead);
1292 #endif
1294 return checkHandshake(bytesRead, true, fd, socketInfo);
1295 }
1297 static int32_t
1298 PSMSend(PRFileDesc* fd, const void* buf, int32_t amount, int flags,
1299 PRIntervalTime timeout)
1300 {
1301 nsNSSShutDownPreventionLock locker;
1302 nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, writing, locker);
1303 if (!socketInfo)
1304 return -1;
1306 if (flags != 0) {
1307 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1308 return -1;
1309 }
1311 #ifdef DEBUG_SSL_VERBOSE
1312 DEBUG_DUMP_BUFFER((unsigned char*) buf, amount);
1313 #endif
1315 int32_t bytesWritten = fd->lower->methods->send(fd->lower, buf, amount,
1316 flags, timeout);
1318 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n",
1319 fd, bytesWritten));
1321 return checkHandshake(bytesWritten, false, fd, socketInfo);
1322 }
1324 static int32_t
1325 nsSSLIOLayerRead(PRFileDesc* fd, void* buf, int32_t amount)
1326 {
1327 return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1328 }
1330 static int32_t
1331 nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, int32_t amount)
1332 {
1333 return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1334 }
1336 static PRStatus
1337 PSMConnectcontinue(PRFileDesc* fd, int16_t out_flags)
1338 {
1339 nsNSSShutDownPreventionLock locker;
1340 if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker)) {
1341 return PR_FAILURE;
1342 }
1344 return fd->lower->methods->connectcontinue(fd, out_flags);
1345 }
1347 static int
1348 PSMAvailable(void)
1349 {
1350 // This is called through PR_Available(), but is not implemented in PSM
1351 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1352 return -1;
1353 }
1355 static int64_t
1356 PSMAvailable64(void)
1357 {
1358 // This is called through PR_Available(), but is not implemented in PSM
1359 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1360 return -1;
1361 }
1363 namespace {
1365 class PrefObserver : public nsIObserver {
1366 public:
1367 NS_DECL_THREADSAFE_ISUPPORTS
1368 NS_DECL_NSIOBSERVER
1369 PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
1370 virtual ~PrefObserver() {}
1371 private:
1372 nsSSLIOLayerHelpers* mOwner;
1373 };
1375 } // unnamed namespace
1377 NS_IMPL_ISUPPORTS(PrefObserver, nsIObserver)
1379 NS_IMETHODIMP
1380 PrefObserver::Observe(nsISupports* aSubject, const char* aTopic,
1381 const char16_t* someData)
1382 {
1383 if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1384 NS_ConvertUTF16toUTF8 prefName(someData);
1386 if (prefName.Equals("security.ssl.renego_unrestricted_hosts")) {
1387 nsCString unrestricted_hosts;
1388 Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
1389 if (!unrestricted_hosts.IsEmpty()) {
1390 mOwner->setRenegoUnrestrictedSites(unrestricted_hosts);
1391 }
1392 } else if (prefName.Equals("security.ssl.treat_unsafe_negotiation_as_broken")) {
1393 bool enabled;
1394 Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
1395 mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
1396 } else if (prefName.Equals("security.ssl.warn_missing_rfc5746")) {
1397 int32_t warnLevel = 1;
1398 Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
1399 mOwner->setWarnLevelMissingRFC5746(warnLevel);
1400 } else if (prefName.Equals("security.ssl.false_start.require-npn")) {
1401 mOwner->mFalseStartRequireNPN =
1402 Preferences::GetBool("security.ssl.false_start.require-npn",
1403 FALSE_START_REQUIRE_NPN_DEFAULT);
1404 } else if (prefName.Equals("security.ssl.false_start.require-forward-secrecy")) {
1405 mOwner->mFalseStartRequireForwardSecrecy =
1406 Preferences::GetBool("security.ssl.false_start.require-forward-secrecy",
1407 FALSE_START_REQUIRE_FORWARD_SECRECY_DEFAULT);
1408 }
1409 }
1410 return NS_OK;
1411 }
1413 static int32_t
1414 PlaintextRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
1415 PRIntervalTime timeout)
1416 {
1417 // The shutdownlocker is not needed here because it will already be
1418 // held higher in the stack
1419 nsNSSSocketInfo* socketInfo = nullptr;
1421 int32_t bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
1422 timeout);
1423 if (fd->identity == nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)
1424 socketInfo = (nsNSSSocketInfo*) fd->secret;
1426 if ((bytesRead > 0) && socketInfo)
1427 socketInfo->AddPlaintextBytesRead(bytesRead);
1428 return bytesRead;
1429 }
1431 nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers()
1432 {
1433 // mPrefObserver will only be set if this->Init was called. The GTest tests
1434 // do not call Init.
1435 if (mPrefObserver) {
1436 Preferences::RemoveObserver(mPrefObserver,
1437 "security.ssl.renego_unrestricted_hosts");
1438 Preferences::RemoveObserver(mPrefObserver,
1439 "security.ssl.treat_unsafe_negotiation_as_broken");
1440 Preferences::RemoveObserver(mPrefObserver,
1441 "security.ssl.warn_missing_rfc5746");
1442 Preferences::RemoveObserver(mPrefObserver,
1443 "security.ssl.false_start.require-npn");
1444 Preferences::RemoveObserver(mPrefObserver,
1445 "security.ssl.false_start.require-forward-secrecy");
1446 }
1447 }
1449 nsresult
1450 nsSSLIOLayerHelpers::Init()
1451 {
1452 if (!nsSSLIOLayerInitialized) {
1453 nsSSLIOLayerInitialized = true;
1454 nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
1455 nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
1457 nsSSLIOLayerMethods.available = (PRAvailableFN) PSMAvailable;
1458 nsSSLIOLayerMethods.available64 = (PRAvailable64FN) PSMAvailable64;
1459 nsSSLIOLayerMethods.fsync = (PRFsyncFN) _PSM_InvalidStatus;
1460 nsSSLIOLayerMethods.seek = (PRSeekFN) _PSM_InvalidInt;
1461 nsSSLIOLayerMethods.seek64 = (PRSeek64FN) _PSM_InvalidInt64;
1462 nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN) _PSM_InvalidStatus;
1463 nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN) _PSM_InvalidStatus;
1464 nsSSLIOLayerMethods.writev = (PRWritevFN) _PSM_InvalidInt;
1465 nsSSLIOLayerMethods.accept = (PRAcceptFN) _PSM_InvalidDesc;
1466 nsSSLIOLayerMethods.bind = (PRBindFN) _PSM_InvalidStatus;
1467 nsSSLIOLayerMethods.listen = (PRListenFN) _PSM_InvalidStatus;
1468 nsSSLIOLayerMethods.shutdown = (PRShutdownFN) _PSM_InvalidStatus;
1469 nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN) _PSM_InvalidInt;
1470 nsSSLIOLayerMethods.sendto = (PRSendtoFN) _PSM_InvalidInt;
1471 nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN) _PSM_InvalidInt;
1472 nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN) _PSM_InvalidInt;
1473 nsSSLIOLayerMethods.sendfile = (PRSendfileFN) _PSM_InvalidInt;
1475 nsSSLIOLayerMethods.getsockname = PSMGetsockname;
1476 nsSSLIOLayerMethods.getpeername = PSMGetpeername;
1477 nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
1478 nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
1479 nsSSLIOLayerMethods.recv = PSMRecv;
1480 nsSSLIOLayerMethods.send = PSMSend;
1481 nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
1483 nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
1484 nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
1485 nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
1486 nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
1487 nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
1489 nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
1490 nsSSLPlaintextLayerMethods = *PR_GetDefaultIOMethods();
1491 nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
1492 }
1494 mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>(16);
1496 nsCString unrestricted_hosts;
1497 Preferences::GetCString("security.ssl.renego_unrestricted_hosts", &unrestricted_hosts);
1498 if (!unrestricted_hosts.IsEmpty()) {
1499 setRenegoUnrestrictedSites(unrestricted_hosts);
1500 }
1502 bool enabled = false;
1503 Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken", &enabled);
1504 setTreatUnsafeNegotiationAsBroken(enabled);
1506 int32_t warnLevel = 1;
1507 Preferences::GetInt("security.ssl.warn_missing_rfc5746", &warnLevel);
1508 setWarnLevelMissingRFC5746(warnLevel);
1510 mFalseStartRequireNPN =
1511 Preferences::GetBool("security.ssl.false_start.require-npn",
1512 FALSE_START_REQUIRE_NPN_DEFAULT);
1513 mFalseStartRequireForwardSecrecy =
1514 Preferences::GetBool("security.ssl.false_start.require-forward-secrecy",
1515 FALSE_START_REQUIRE_FORWARD_SECRECY_DEFAULT);
1517 mPrefObserver = new PrefObserver(this);
1518 Preferences::AddStrongObserver(mPrefObserver,
1519 "security.ssl.renego_unrestricted_hosts");
1520 Preferences::AddStrongObserver(mPrefObserver,
1521 "security.ssl.treat_unsafe_negotiation_as_broken");
1522 Preferences::AddStrongObserver(mPrefObserver,
1523 "security.ssl.warn_missing_rfc5746");
1524 Preferences::AddStrongObserver(mPrefObserver,
1525 "security.ssl.false_start.require-npn");
1526 Preferences::AddStrongObserver(mPrefObserver,
1527 "security.ssl.false_start.require-forward-secrecy");
1528 return NS_OK;
1529 }
1531 void
1532 nsSSLIOLayerHelpers::clearStoredData()
1533 {
1534 mRenegoUnrestrictedSites->Clear();
1535 mTLSIntoleranceInfo.Clear();
1536 }
1538 void
1539 nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString& str)
1540 {
1541 MutexAutoLock lock(mutex);
1543 if (mRenegoUnrestrictedSites) {
1544 delete mRenegoUnrestrictedSites;
1545 mRenegoUnrestrictedSites = nullptr;
1546 }
1548 mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
1549 if (!mRenegoUnrestrictedSites)
1550 return;
1552 nsCCharSeparatedTokenizer toker(str, ',');
1554 while (toker.hasMoreTokens()) {
1555 const nsCSubstring& host = toker.nextToken();
1556 if (!host.IsEmpty()) {
1557 mRenegoUnrestrictedSites->PutEntry(host);
1558 }
1559 }
1560 }
1562 bool
1563 nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString& str)
1564 {
1565 MutexAutoLock lock(mutex);
1566 return mRenegoUnrestrictedSites->Contains(str);
1567 }
1569 void
1570 nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
1571 {
1572 MutexAutoLock lock(mutex);
1573 mTreatUnsafeNegotiationAsBroken = broken;
1574 }
1576 bool
1577 nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
1578 {
1579 MutexAutoLock lock(mutex);
1580 return mTreatUnsafeNegotiationAsBroken;
1581 }
1583 void
1584 nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(int32_t level)
1585 {
1586 MutexAutoLock lock(mutex);
1587 mWarnLevelMissingRFC5746 = level;
1588 }
1590 int32_t
1591 nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746()
1592 {
1593 MutexAutoLock lock(mutex);
1594 return mWarnLevelMissingRFC5746;
1595 }
1597 nsresult
1598 nsSSLIOLayerNewSocket(int32_t family,
1599 const char* host,
1600 int32_t port,
1601 nsIProxyInfo *proxy,
1602 PRFileDesc** fd,
1603 nsISupports** info,
1604 bool forSTARTTLS,
1605 uint32_t flags)
1606 {
1608 PRFileDesc* sock = PR_OpenTCPSocket(family);
1609 if (!sock) return NS_ERROR_OUT_OF_MEMORY;
1611 nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxy,
1612 sock, info, forSTARTTLS, flags);
1613 if (NS_FAILED(rv)) {
1614 PR_Close(sock);
1615 return rv;
1616 }
1618 *fd = sock;
1619 return NS_OK;
1620 }
1622 // Creates CA names strings from (CERTDistNames* caNames)
1623 //
1624 // - arena: arena to allocate strings on
1625 // - caNameStrings: filled with CA names strings on return
1626 // - caNames: CERTDistNames to extract strings from
1627 // - return: SECSuccess if successful; error code otherwise
1628 //
1629 // Note: copied in its entirety from Nova code
1630 static SECStatus
1631 nsConvertCANamesToStrings(PLArenaPool* arena, char** caNameStrings,
1632 CERTDistNames* caNames)
1633 {
1634 SECItem* dername;
1635 SECStatus rv;
1636 int headerlen;
1637 uint32_t contentlen;
1638 SECItem newitem;
1639 int n;
1640 char* namestring;
1642 for (n = 0; n < caNames->nnames; n++) {
1643 newitem.data = nullptr;
1644 dername = &caNames->names[n];
1646 rv = DER_Lengths(dername, &headerlen, &contentlen);
1648 if (rv != SECSuccess) {
1649 goto loser;
1650 }
1652 if (headerlen + contentlen != dername->len) {
1653 // This must be from an enterprise 2.x server, which sent
1654 // incorrectly formatted der without the outer wrapper of type and
1655 // length. Fix it up by adding the top level header.
1656 if (dername->len <= 127) {
1657 newitem.data = (unsigned char*) PR_Malloc(dername->len + 2);
1658 if (!newitem.data) {
1659 goto loser;
1660 }
1661 newitem.data[0] = (unsigned char) 0x30;
1662 newitem.data[1] = (unsigned char) dername->len;
1663 (void) memcpy(&newitem.data[2], dername->data, dername->len);
1664 } else if (dername->len <= 255) {
1665 newitem.data = (unsigned char*) PR_Malloc(dername->len + 3);
1666 if (!newitem.data) {
1667 goto loser;
1668 }
1669 newitem.data[0] = (unsigned char) 0x30;
1670 newitem.data[1] = (unsigned char) 0x81;
1671 newitem.data[2] = (unsigned char) dername->len;
1672 (void) memcpy(&newitem.data[3], dername->data, dername->len);
1673 } else {
1674 // greater than 256, better be less than 64k
1675 newitem.data = (unsigned char*) PR_Malloc(dername->len + 4);
1676 if (!newitem.data) {
1677 goto loser;
1678 }
1679 newitem.data[0] = (unsigned char) 0x30;
1680 newitem.data[1] = (unsigned char) 0x82;
1681 newitem.data[2] = (unsigned char) ((dername->len >> 8) & 0xff);
1682 newitem.data[3] = (unsigned char) (dername->len & 0xff);
1683 memcpy(&newitem.data[4], dername->data, dername->len);
1684 }
1685 dername = &newitem;
1686 }
1688 namestring = CERT_DerNameToAscii(dername);
1689 if (!namestring) {
1690 // XXX - keep going until we fail to convert the name
1691 caNameStrings[n] = const_cast<char*>("");
1692 } else {
1693 caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
1694 PR_Free(namestring);
1695 if (!caNameStrings[n]) {
1696 goto loser;
1697 }
1698 }
1700 if (newitem.data) {
1701 PR_Free(newitem.data);
1702 }
1703 }
1705 return SECSuccess;
1706 loser:
1707 if (newitem.data) {
1708 PR_Free(newitem.data);
1709 }
1710 return SECFailure;
1711 }
1713 // Sets certChoice by reading the preference
1714 //
1715 // If done properly, this function will read the identifier strings for ASK and
1716 // AUTO modes read the selected strings from the preference, compare the
1717 // strings, and determine in which mode it is in. We currently use ASK mode for
1718 // UI apps and AUTO mode for UI-less apps without really asking for
1719 // preferences.
1720 nsresult
1721 nsGetUserCertChoice(SSM_UserCertChoice* certChoice)
1722 {
1723 char* mode = nullptr;
1724 nsresult ret;
1726 NS_ENSURE_ARG_POINTER(certChoice);
1728 nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
1730 ret = pref->GetCharPref("security.default_personal_cert", &mode);
1731 if (NS_FAILED(ret)) {
1732 goto loser;
1733 }
1735 if (PL_strcmp(mode, "Select Automatically") == 0) {
1736 *certChoice = AUTO;
1737 } else if (PL_strcmp(mode, "Ask Every Time") == 0) {
1738 *certChoice = ASK;
1739 } else {
1740 // Most likely we see a nickname from a migrated cert.
1741 // We do not currently support that, ask the user which cert to use.
1742 *certChoice = ASK;
1743 }
1745 loser:
1746 if (mode) {
1747 nsMemory::Free(mode);
1748 }
1749 return ret;
1750 }
1752 static bool
1753 hasExplicitKeyUsageNonRepudiation(CERTCertificate* cert)
1754 {
1755 // There is no extension, v1 or v2 certificate
1756 if (!cert->extensions)
1757 return false;
1759 SECStatus srv;
1760 SECItem keyUsageItem;
1761 keyUsageItem.data = nullptr;
1763 srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
1764 if (srv == SECFailure)
1765 return false;
1767 unsigned char keyUsage = keyUsageItem.data[0];
1768 PORT_Free (keyUsageItem.data);
1770 return !!(keyUsage & KU_NON_REPUDIATION);
1771 }
1773 class ClientAuthDataRunnable : public SyncRunnableBase
1774 {
1775 public:
1776 ClientAuthDataRunnable(CERTDistNames* caNames,
1777 CERTCertificate** pRetCert,
1778 SECKEYPrivateKey** pRetKey,
1779 nsNSSSocketInfo* info,
1780 CERTCertificate* serverCert)
1781 : mRV(SECFailure)
1782 , mErrorCodeToReport(SEC_ERROR_NO_MEMORY)
1783 , mPRetCert(pRetCert)
1784 , mPRetKey(pRetKey)
1785 , mCANames(caNames)
1786 , mSocketInfo(info)
1787 , mServerCert(serverCert)
1788 {
1789 }
1791 SECStatus mRV; // out
1792 PRErrorCode mErrorCodeToReport; // out
1793 CERTCertificate** const mPRetCert; // in/out
1794 SECKEYPrivateKey** const mPRetKey; // in/out
1795 protected:
1796 virtual void RunOnTargetThread();
1797 private:
1798 CERTDistNames* const mCANames; // in
1799 nsNSSSocketInfo* const mSocketInfo; // in
1800 CERTCertificate* const mServerCert; // in
1801 };
1803 // This callback function is used to pull client certificate
1804 // information upon server request
1805 //
1806 // - arg: SSL data connection
1807 // - socket: SSL socket we're dealing with
1808 // - caNames: list of CA names
1809 // - pRetCert: returns a pointer to a pointer to a valid certificate if
1810 // successful; otherwise nullptr
1811 // - pRetKey: returns a pointer to a pointer to the corresponding key if
1812 // successful; otherwise nullptr
1813 SECStatus
1814 nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
1815 CERTDistNames* caNames, CERTCertificate** pRetCert,
1816 SECKEYPrivateKey** pRetKey)
1817 {
1818 nsNSSShutDownPreventionLock locker;
1820 if (!socket || !caNames || !pRetCert || !pRetKey) {
1821 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1822 return SECFailure;
1823 }
1825 RefPtr<nsNSSSocketInfo> info(
1826 reinterpret_cast<nsNSSSocketInfo*>(socket->higher->secret));
1828 CERTCertificate* serverCert = SSL_PeerCertificate(socket);
1829 if (!serverCert) {
1830 NS_NOTREACHED("Missing server certificate should have been detected during "
1831 "server cert authentication.");
1832 PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
1833 return SECFailure;
1834 }
1836 if (info->GetJoined()) {
1837 // We refuse to send a client certificate when there are multiple hostnames
1838 // joined on this connection, because we only show the user one hostname
1839 // (mHostName) in the client certificate UI.
1841 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1842 ("[%p] Not returning client cert due to previous join\n", socket));
1843 *pRetCert = nullptr;
1844 *pRetKey = nullptr;
1845 return SECSuccess;
1846 }
1848 // XXX: This should be done asynchronously; see bug 696976
1849 RefPtr<ClientAuthDataRunnable> runnable(
1850 new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert));
1851 nsresult rv = runnable->DispatchToMainThreadAndWait();
1852 if (NS_FAILED(rv)) {
1853 PR_SetError(SEC_ERROR_NO_MEMORY, 0);
1854 return SECFailure;
1855 }
1857 if (runnable->mRV != SECSuccess) {
1858 PR_SetError(runnable->mErrorCodeToReport, 0);
1859 } else if (*runnable->mPRetCert || *runnable->mPRetKey) {
1860 // Make joinConnection prohibit joining after we've sent a client cert
1861 info->SetSentClientCert();
1862 }
1864 return runnable->mRV;
1865 }
1867 void
1868 ClientAuthDataRunnable::RunOnTargetThread()
1869 {
1870 PLArenaPool* arena = nullptr;
1871 char** caNameStrings;
1872 mozilla::pkix::ScopedCERTCertificate cert;
1873 ScopedSECKEYPrivateKey privKey;
1874 mozilla::pkix::ScopedCERTCertList certList;
1875 CERTCertListNode* node;
1876 ScopedCERTCertNicknames nicknames;
1877 int keyError = 0; // used for private key retrieval error
1878 SSM_UserCertChoice certChoice;
1879 int32_t NumberOfCerts = 0;
1880 void* wincx = mSocketInfo;
1881 nsresult rv;
1883 // create caNameStrings
1884 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1885 if (!arena) {
1886 goto loser;
1887 }
1889 caNameStrings = (char**) PORT_ArenaAlloc(arena,
1890 sizeof(char*) * (mCANames->nnames));
1891 if (!caNameStrings) {
1892 goto loser;
1893 }
1895 mRV = nsConvertCANamesToStrings(arena, caNameStrings, mCANames);
1896 if (mRV != SECSuccess) {
1897 goto loser;
1898 }
1900 // get the preference
1901 if (NS_FAILED(nsGetUserCertChoice(&certChoice))) {
1902 goto loser;
1903 }
1905 // find valid user cert and key pair
1906 if (certChoice == AUTO) {
1907 // automatically find the right cert
1909 // find all user certs that are valid and for SSL
1910 certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
1911 certUsageSSLClient, false,
1912 true, wincx);
1913 if (!certList) {
1914 goto noCert;
1915 }
1917 // filter the list to those issued by CAs supported by the server
1918 mRV = CERT_FilterCertListByCANames(certList.get(), mCANames->nnames,
1919 caNameStrings, certUsageSSLClient);
1920 if (mRV != SECSuccess) {
1921 goto noCert;
1922 }
1924 // make sure the list is not empty
1925 node = CERT_LIST_HEAD(certList);
1926 if (CERT_LIST_END(node, certList)) {
1927 goto noCert;
1928 }
1930 ScopedCERTCertificate low_prio_nonrep_cert;
1932 // loop through the list until we find a cert with a key
1933 while (!CERT_LIST_END(node, certList)) {
1934 // if the certificate has restriction and we do not satisfy it we do not
1935 // use it
1936 privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
1937 if (privKey) {
1938 if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
1939 privKey = nullptr;
1940 // Not a prefered cert
1941 if (!low_prio_nonrep_cert) { // did not yet find a low prio cert
1942 low_prio_nonrep_cert = CERT_DupCertificate(node->cert);
1943 }
1944 } else {
1945 // this is a good cert to present
1946 cert = CERT_DupCertificate(node->cert);
1947 break;
1948 }
1949 }
1950 keyError = PR_GetError();
1951 if (keyError == SEC_ERROR_BAD_PASSWORD) {
1952 // problem with password: bail
1953 goto loser;
1954 }
1956 node = CERT_LIST_NEXT(node);
1957 }
1959 if (!cert && low_prio_nonrep_cert) {
1960 cert = low_prio_nonrep_cert.forget();
1961 privKey = PK11_FindKeyByAnyCert(cert.get(), wincx);
1962 }
1964 if (!cert) {
1965 goto noCert;
1966 }
1967 } else { // Not Auto => ask
1968 // Get the SSL Certificate
1970 nsXPIDLCString hostname;
1971 mSocketInfo->GetHostName(getter_Copies(hostname));
1973 RefPtr<nsClientAuthRememberService> cars =
1974 mSocketInfo->SharedState().GetClientAuthRememberService();
1976 bool hasRemembered = false;
1977 nsCString rememberedDBKey;
1978 if (cars) {
1979 bool found;
1980 rv = cars->HasRememberedDecision(hostname, mServerCert,
1981 rememberedDBKey, &found);
1982 if (NS_SUCCEEDED(rv) && found) {
1983 hasRemembered = true;
1984 }
1985 }
1987 bool canceled = false;
1989 if (hasRemembered) {
1990 if (rememberedDBKey.IsEmpty()) {
1991 canceled = true;
1992 } else {
1993 nsCOMPtr<nsIX509CertDB> certdb;
1994 certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
1995 if (certdb) {
1996 nsCOMPtr<nsIX509Cert> found_cert;
1997 nsresult find_rv =
1998 certdb->FindCertByDBKey(rememberedDBKey.get(), nullptr,
1999 getter_AddRefs(found_cert));
2000 if (NS_SUCCEEDED(find_rv) && found_cert) {
2001 nsNSSCertificate* obj_cert =
2002 reinterpret_cast<nsNSSCertificate*>(found_cert.get());
2003 if (obj_cert) {
2004 cert = obj_cert->GetCert();
2005 }
2006 }
2008 if (!cert) {
2009 hasRemembered = false;
2010 }
2011 }
2012 }
2013 }
2015 if (!hasRemembered) {
2016 // user selects a cert to present
2017 nsIClientAuthDialogs* dialogs = nullptr;
2018 int32_t selectedIndex = -1;
2019 char16_t** certNicknameList = nullptr;
2020 char16_t** certDetailsList = nullptr;
2022 // find all user certs that are for SSL
2023 // note that we are allowing expired certs in this list
2024 certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
2025 certUsageSSLClient, false,
2026 false, wincx);
2027 if (!certList) {
2028 goto noCert;
2029 }
2031 if (mCANames->nnames != 0) {
2032 // filter the list to those issued by CAs supported by the server
2033 mRV = CERT_FilterCertListByCANames(certList.get(),
2034 mCANames->nnames,
2035 caNameStrings,
2036 certUsageSSLClient);
2037 if (mRV != SECSuccess) {
2038 goto loser;
2039 }
2040 }
2042 if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
2043 // list is empty - no matching certs
2044 goto noCert;
2045 }
2047 // filter it further for hostname restriction
2048 node = CERT_LIST_HEAD(certList.get());
2049 while (!CERT_LIST_END(node, certList.get())) {
2050 ++NumberOfCerts;
2051 node = CERT_LIST_NEXT(node);
2052 }
2053 if (CERT_LIST_END(CERT_LIST_HEAD(certList.get()), certList.get())) {
2054 goto noCert;
2055 }
2057 nicknames = getNSSCertNicknamesFromCertList(certList.get());
2059 if (!nicknames) {
2060 goto loser;
2061 }
2063 NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");
2065 // Get CN and O of the subject and O of the issuer
2066 char* ccn = CERT_GetCommonName(&mServerCert->subject);
2067 void* v = ccn;
2068 voidCleaner ccnCleaner(v);
2069 NS_ConvertUTF8toUTF16 cn(ccn);
2071 int32_t port;
2072 mSocketInfo->GetPort(&port);
2074 nsString cn_host_port;
2075 if (ccn && strcmp(ccn, hostname) == 0) {
2076 cn_host_port.Append(cn);
2077 cn_host_port.AppendLiteral(":");
2078 cn_host_port.AppendInt(port);
2079 } else {
2080 cn_host_port.Append(cn);
2081 cn_host_port.AppendLiteral(" (");
2082 cn_host_port.AppendLiteral(":");
2083 cn_host_port.AppendInt(port);
2084 cn_host_port.AppendLiteral(")");
2085 }
2087 char* corg = CERT_GetOrgName(&mServerCert->subject);
2088 NS_ConvertUTF8toUTF16 org(corg);
2089 if (corg) PORT_Free(corg);
2091 char* cissuer = CERT_GetOrgName(&mServerCert->issuer);
2092 NS_ConvertUTF8toUTF16 issuer(cissuer);
2093 if (cissuer) PORT_Free(cissuer);
2095 certNicknameList =
2096 (char16_t**)nsMemory::Alloc(sizeof(char16_t*)* nicknames->numnicknames);
2097 if (!certNicknameList)
2098 goto loser;
2099 certDetailsList =
2100 (char16_t**)nsMemory::Alloc(sizeof(char16_t*)* nicknames->numnicknames);
2101 if (!certDetailsList) {
2102 nsMemory::Free(certNicknameList);
2103 goto loser;
2104 }
2106 int32_t CertsToUse;
2107 for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
2108 !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
2109 node = CERT_LIST_NEXT(node)
2110 ) {
2111 RefPtr<nsNSSCertificate> tempCert(nsNSSCertificate::Create(node->cert));
2113 if (!tempCert)
2114 continue;
2116 NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
2117 nsAutoString nickWithSerial, details;
2119 if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
2120 continue;
2122 certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
2123 if (!certNicknameList[CertsToUse])
2124 continue;
2125 certDetailsList[CertsToUse] = ToNewUnicode(details);
2126 if (!certDetailsList[CertsToUse]) {
2127 nsMemory::Free(certNicknameList[CertsToUse]);
2128 continue;
2129 }
2131 ++CertsToUse;
2132 }
2134 // Throw up the client auth dialog and get back the index of the selected cert
2135 nsresult rv = getNSSDialogs((void**)&dialogs,
2136 NS_GET_IID(nsIClientAuthDialogs),
2137 NS_CLIENTAUTHDIALOGS_CONTRACTID);
2139 if (NS_FAILED(rv)) {
2140 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
2141 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
2142 goto loser;
2143 }
2145 {
2146 nsPSMUITracker tracker;
2147 if (tracker.isUIForbidden()) {
2148 rv = NS_ERROR_NOT_AVAILABLE;
2149 } else {
2150 rv = dialogs->ChooseCertificate(mSocketInfo, cn_host_port.get(),
2151 org.get(), issuer.get(),
2152 (const char16_t**)certNicknameList,
2153 (const char16_t**)certDetailsList,
2154 CertsToUse, &selectedIndex, &canceled);
2155 }
2156 }
2158 NS_RELEASE(dialogs);
2159 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
2160 NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
2162 if (NS_FAILED(rv)) goto loser;
2164 // even if the user has canceled, we want to remember that, to avoid repeating prompts
2165 bool wantRemember = false;
2166 mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
2168 int i;
2169 if (!canceled)
2170 for (i = 0, node = CERT_LIST_HEAD(certList);
2171 !CERT_LIST_END(node, certList);
2172 ++i, node = CERT_LIST_NEXT(node)) {
2174 if (i == selectedIndex) {
2175 cert = CERT_DupCertificate(node->cert);
2176 break;
2177 }
2178 }
2180 if (cars && wantRemember) {
2181 cars->RememberDecision(hostname, mServerCert,
2182 canceled ? nullptr : cert.get());
2183 }
2184 }
2186 if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
2188 if (!cert) {
2189 goto loser;
2190 }
2192 // go get the private key
2193 privKey = PK11_FindKeyByAnyCert(cert.get(), wincx);
2194 if (!privKey) {
2195 keyError = PR_GetError();
2196 if (keyError == SEC_ERROR_BAD_PASSWORD) {
2197 // problem with password: bail
2198 goto loser;
2199 } else {
2200 goto noCert;
2201 }
2202 }
2203 }
2204 goto done;
2206 noCert:
2207 loser:
2208 if (mRV == SECSuccess) {
2209 mRV = SECFailure;
2210 }
2211 done:
2212 int error = PR_GetError();
2214 if (arena) {
2215 PORT_FreeArena(arena, false);
2216 }
2218 *mPRetCert = cert.release();
2219 *mPRetKey = privKey.forget();
2221 if (mRV == SECFailure) {
2222 mErrorCodeToReport = error;
2223 }
2224 }
2226 static PRFileDesc*
2227 nsSSLIOLayerImportFD(PRFileDesc* fd,
2228 nsNSSSocketInfo* infoObject,
2229 const char* host)
2230 {
2231 nsNSSShutDownPreventionLock locker;
2232 PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd);
2233 if (!sslSock) {
2234 NS_ASSERTION(false, "NSS: Error importing socket");
2235 return nullptr;
2236 }
2237 SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*) infoObject);
2238 SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
2239 SSL_SetCanFalseStartCallback(sslSock, CanFalseStartCallback, infoObject);
2241 // Disable this hook if we connect anonymously. See bug 466080.
2242 uint32_t flags = 0;
2243 infoObject->GetProviderFlags(&flags);
2244 if (flags & nsISocketProvider::ANONYMOUS_CONNECT) {
2245 SSL_GetClientAuthDataHook(sslSock, nullptr, infoObject);
2246 } else {
2247 SSL_GetClientAuthDataHook(sslSock,
2248 (SSLGetClientAuthData) nsNSS_SSLGetClientAuthData,
2249 infoObject);
2250 }
2251 if (SECSuccess != SSL_AuthCertificateHook(sslSock, AuthCertificateHook,
2252 infoObject)) {
2253 NS_NOTREACHED("failed to configure AuthCertificateHook");
2254 goto loser;
2255 }
2257 if (SECSuccess != SSL_SetURL(sslSock, host)) {
2258 NS_NOTREACHED("SSL_SetURL failed");
2259 goto loser;
2260 }
2262 // This is an optimization to make sure the identity info dataset is parsed
2263 // and loaded on a separate thread and can be overlapped with network latency.
2264 EnsureServerVerificationInitialized();
2266 return sslSock;
2267 loser:
2268 if (sslSock) {
2269 PR_Close(sslSock);
2270 }
2271 return nullptr;
2272 }
2274 static nsresult
2275 nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
2276 bool haveProxy, const char* host, int32_t port,
2277 nsNSSSocketInfo* infoObject)
2278 {
2279 nsNSSShutDownPreventionLock locker;
2280 if (forSTARTTLS || haveProxy) {
2281 if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
2282 return NS_ERROR_FAILURE;
2283 }
2284 }
2286 // Let's see if we're trying to connect to a site we know is
2287 // TLS intolerant.
2288 nsAutoCString key;
2289 key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
2291 SSLVersionRange range;
2292 if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
2293 return NS_ERROR_FAILURE;
2294 }
2296 uint16_t maxEnabledVersion = range.max;
2298 infoObject->SharedState().IOLayerHelpers()
2299 .adjustForTLSIntolerance(infoObject->GetHostName(), infoObject->GetPort(),
2300 range);
2301 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
2302 ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
2303 fd, static_cast<unsigned int>(range.min),
2304 static_cast<unsigned int>(range.max)));
2306 if (SSL_VersionRangeSet(fd, &range) != SECSuccess) {
2307 return NS_ERROR_FAILURE;
2308 }
2309 infoObject->SetTLSVersionRange(range);
2311 // when adjustForTLSIntolerance tweaks the maximum version downward,
2312 // we tell the server using this SCSV so they can detect a downgrade attack
2313 if (range.max < maxEnabledVersion) {
2314 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
2315 ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
2316 if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
2317 return NS_ERROR_FAILURE;
2318 }
2319 }
2321 bool enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
2322 if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) {
2323 return NS_ERROR_FAILURE;
2324 }
2326 if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
2327 return NS_ERROR_FAILURE;
2328 }
2330 nsSSLIOLayerHelpers& ioHelpers = infoObject->SharedState().IOLayerHelpers();
2331 if (ioHelpers.isRenegoUnrestrictedSite(nsDependentCString(host))) {
2332 if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
2333 return NS_ERROR_FAILURE;
2334 }
2335 if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED)) {
2336 return NS_ERROR_FAILURE;
2337 }
2338 }
2340 // Set the Peer ID so that SSL proxy connections work properly and to
2341 // separate anonymous and/or private browsing connections.
2342 uint32_t flags = infoObject->GetProviderFlags();
2343 nsAutoCString peerId;
2344 if (flags & nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
2345 peerId.Append("anon:");
2346 }
2347 if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
2348 peerId.Append("private:");
2349 }
2350 peerId.Append(host);
2351 peerId.Append(':');
2352 peerId.AppendInt(port);
2353 if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
2354 return NS_ERROR_FAILURE;
2355 }
2357 return NS_OK;
2358 }
2360 nsresult
2361 nsSSLIOLayerAddToSocket(int32_t family,
2362 const char* host,
2363 int32_t port,
2364 nsIProxyInfo* proxy,
2365 PRFileDesc* fd,
2366 nsISupports** info,
2367 bool forSTARTTLS,
2368 uint32_t providerFlags)
2369 {
2370 nsNSSShutDownPreventionLock locker;
2371 PRFileDesc* layer = nullptr;
2372 PRFileDesc* plaintextLayer = nullptr;
2373 nsresult rv;
2374 PRStatus stat;
2376 SharedSSLState* sharedState =
2377 providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ? PrivateSSLState() : PublicSSLState();
2378 nsNSSSocketInfo* infoObject = new nsNSSSocketInfo(*sharedState, providerFlags);
2379 if (!infoObject) return NS_ERROR_FAILURE;
2381 NS_ADDREF(infoObject);
2382 infoObject->SetForSTARTTLS(forSTARTTLS);
2383 infoObject->SetHostName(host);
2384 infoObject->SetPort(port);
2386 bool haveProxy = false;
2387 if (proxy) {
2388 nsCString proxyHost;
2389 proxy->GetHost(proxyHost);
2390 haveProxy = !proxyHost.IsEmpty();
2391 }
2393 // A plaintext observer shim is inserted so we can observe some protocol
2394 // details without modifying nss
2395 plaintextLayer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity,
2396 &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods);
2397 if (plaintextLayer) {
2398 plaintextLayer->secret = (PRFilePrivate*) infoObject;
2399 stat = PR_PushIOLayer(fd, PR_TOP_IO_LAYER, plaintextLayer);
2400 if (stat == PR_FAILURE) {
2401 plaintextLayer->dtor(plaintextLayer);
2402 plaintextLayer = nullptr;
2403 }
2404 }
2406 PRFileDesc* sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
2407 if (!sslSock) {
2408 NS_ASSERTION(false, "NSS: Error importing socket");
2409 goto loser;
2410 }
2412 infoObject->SetFileDescPtr(sslSock);
2414 rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, haveProxy, host, port,
2415 infoObject);
2417 if (NS_FAILED(rv))
2418 goto loser;
2420 // Now, layer ourselves on top of the SSL socket...
2421 layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
2422 &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
2423 if (!layer)
2424 goto loser;
2426 layer->secret = (PRFilePrivate*) infoObject;
2427 stat = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
2429 if (stat == PR_FAILURE) {
2430 goto loser;
2431 }
2433 nsNSSShutDownList::trackSSLSocketCreate();
2435 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*) sslSock));
2436 infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
2438 // We are going use a clear connection first //
2439 if (forSTARTTLS || haveProxy) {
2440 infoObject->SetHandshakeNotPending();
2441 }
2443 infoObject->SharedState().NoteSocketCreated();
2445 return NS_OK;
2446 loser:
2447 NS_IF_RELEASE(infoObject);
2448 if (layer) {
2449 layer->dtor(layer);
2450 }
2451 if (plaintextLayer) {
2452 PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
2453 plaintextLayer->dtor(plaintextLayer);
2454 }
2455 return NS_ERROR_FAILURE;
2456 }