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/. */
6 
7 #include "nsNSSIOLayer.h"
8 
9 #include <algorithm>
10 
11 #include "NSSCertDBTrustDomain.h"
12 #include "NSSErrorsService.h"
13 #include "PSMRunnable.h"
14 #include "SSLServerCertVerification.h"
15 #include "ScopedNSSTypes.h"
16 #include "SharedSSLState.h"
17 #include "keyhi.h"
18 #include "mozilla/Casting.h"
19 #include "mozilla/DebugOnly.h"
20 #include "mozilla/Logging.h"
21 #include "mozilla/Move.h"
22 #include "mozilla/Preferences.h"
23 #include "mozilla/Telemetry.h"
24 #include "nsArray.h"
25 #include "nsArrayUtils.h"
26 #include "nsCRT.h"
27 #include "nsCharSeparatedTokenizer.h"
28 #include "nsClientAuthRemember.h"
29 #include "nsContentUtils.h"
30 #include "nsIClientAuthDialogs.h"
31 #include "nsIConsoleService.h"
32 #include "nsIPrefService.h"
33 #include "nsISocketProvider.h"
34 #include "nsIWebProgressListener.h"
35 #include "nsNSSCertHelper.h"
36 #include "nsNSSComponent.h"
37 #include "nsPrintfCString.h"
38 #include "nsServiceManagerUtils.h"
39 #include "pkix/pkixtypes.h"
40 #include "prmem.h"
41 #include "prnetdb.h"
42 #include "secder.h"
43 #include "secerr.h"
44 #include "ssl.h"
45 #include "sslerr.h"
46 #include "sslproto.h"
47 #include "sslexp.h"
48 
49 using namespace mozilla;
50 using namespace mozilla::psm;
51 
52 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
53 // reports when doing SSL read/write
54 
55 //#define DUMP_BUFFER  //Enable this define along with
56 // DEBUG_SSL_VERBOSE to dump SSL
57 // read/write buffer to a log.
58 // Uses PR_LOG except on Mac where
59 // we always write out to our own
60 // file.
61 
62 namespace {
63 
64 // The NSSSocketInfo tls flags are meant to be opaque to most calling
65 // applications but provide a mechanism for direct TLS manipulation when
66 // experimenting with new features in the scope of a single socket. They do not
67 // create a persistent ABI.
68 //
69 // Use of these flags creates a new 'sharedSSLState' so existing states for
70 // intolerance are not carried to sockets that use these flags (and intolerance
71 // they discover does not impact other normal sockets not using the flags.)
72 //
73 // Their current definitions are:
74 //
75 // bits 0-2 (mask 0x07) specify the max tls version
76 //          0 means no override 1->4 are 1.0, 1.1, 1.2, 1.3, 4->7 unused
77 // bits 3-5 (mask 0x38) specify the tls fallback limit
78 //          0 means no override, values 1->4 match prefs
79 // bit    6 (mask 0x40) was used to specify compat mode. Temporarily reserved.
80 
81 enum {
82   kTLSProviderFlagMaxVersion10 = 0x01,
83   kTLSProviderFlagMaxVersion11 = 0x02,
84   kTLSProviderFlagMaxVersion12 = 0x03,
85   kTLSProviderFlagMaxVersion13 = 0x04,
86 };
87 
getTLSProviderFlagMaxVersion(uint32_t flags)88 static uint32_t getTLSProviderFlagMaxVersion(uint32_t flags) {
89   return (flags & 0x07);
90 }
91 
getTLSProviderFlagFallbackLimit(uint32_t flags)92 static uint32_t getTLSProviderFlagFallbackLimit(uint32_t flags) {
93   return (flags & 0x38) >> 3;
94 }
95 
96 #define MAX_ALPN_LENGTH 255
97 
getSiteKey(const nsACString & hostName,uint16_t port,nsACString & key)98 void getSiteKey(const nsACString& hostName, uint16_t port,
99                 /*out*/ nsACString& key) {
100   key = hostName;
101   key.AppendASCII(":");
102   key.AppendInt(port);
103 }
104 
105 }  // unnamed namespace
106 
107 extern LazyLogModule gPIPNSSLog;
108 
nsNSSSocketInfo(SharedSSLState & aState,uint32_t providerFlags,uint32_t providerTlsFlags)109 nsNSSSocketInfo::nsNSSSocketInfo(SharedSSLState& aState, uint32_t providerFlags,
110                                  uint32_t providerTlsFlags)
111     : mFd(nullptr),
112       mCertVerificationState(before_cert_verification),
113       mSharedState(aState),
114       mForSTARTTLS(false),
115       mHandshakePending(true),
116       mRememberClientAuthCertificate(false),
117       mPreliminaryHandshakeDone(false),
118       mNPNCompleted(false),
119       mEarlyDataAccepted(false),
120       mDenyClientCert(false),
121       mFalseStartCallbackCalled(false),
122       mFalseStarted(false),
123       mIsFullHandshake(false),
124       mHandshakeCompleted(false),
125       mJoined(false),
126       mSentClientCert(false),
127       mNotedTimeUntilReady(false),
128       mFailedVerification(false),
129       mIsShortWritePending(false),
130       mShortWritePendingByte(0),
131       mShortWriteOriginalAmount(-1),
132       mKEAUsed(nsISSLSocketControl::KEY_EXCHANGE_UNKNOWN),
133       mKEAKeyBits(0),
134       mSSLVersionUsed(nsISSLSocketControl::SSL_VERSION_UNKNOWN),
135       mMACAlgorithmUsed(nsISSLSocketControl::SSL_MAC_UNKNOWN),
136       mBypassAuthentication(false),
137       mProviderFlags(providerFlags),
138       mProviderTlsFlags(providerTlsFlags),
139       mSocketCreationTimestamp(TimeStamp::Now()),
140       mPlaintextBytesRead(0),
141       mClientCert(nullptr) {
142   mTLSVersionRange.min = 0;
143   mTLSVersionRange.max = 0;
144 }
145 
~nsNSSSocketInfo()146 nsNSSSocketInfo::~nsNSSSocketInfo() {}
147 
NS_IMPL_ISUPPORTS_INHERITED(nsNSSSocketInfo,TransportSecurityInfo,nsISSLSocketControl,nsIClientAuthUserDecision)148 NS_IMPL_ISUPPORTS_INHERITED(nsNSSSocketInfo, TransportSecurityInfo,
149                             nsISSLSocketControl, nsIClientAuthUserDecision)
150 
151 NS_IMETHODIMP
152 nsNSSSocketInfo::GetProviderFlags(uint32_t* aProviderFlags) {
153   *aProviderFlags = mProviderFlags;
154   return NS_OK;
155 }
156 
157 NS_IMETHODIMP
GetProviderTlsFlags(uint32_t * aProviderTlsFlags)158 nsNSSSocketInfo::GetProviderTlsFlags(uint32_t* aProviderTlsFlags) {
159   *aProviderTlsFlags = mProviderTlsFlags;
160   return NS_OK;
161 }
162 
163 NS_IMETHODIMP
GetKEAUsed(int16_t * aKea)164 nsNSSSocketInfo::GetKEAUsed(int16_t* aKea) {
165   *aKea = mKEAUsed;
166   return NS_OK;
167 }
168 
169 NS_IMETHODIMP
GetKEAKeyBits(uint32_t * aKeyBits)170 nsNSSSocketInfo::GetKEAKeyBits(uint32_t* aKeyBits) {
171   *aKeyBits = mKEAKeyBits;
172   return NS_OK;
173 }
174 
175 NS_IMETHODIMP
GetSSLVersionUsed(int16_t * aSSLVersionUsed)176 nsNSSSocketInfo::GetSSLVersionUsed(int16_t* aSSLVersionUsed) {
177   *aSSLVersionUsed = mSSLVersionUsed;
178   return NS_OK;
179 }
180 
181 NS_IMETHODIMP
GetSSLVersionOffered(int16_t * aSSLVersionOffered)182 nsNSSSocketInfo::GetSSLVersionOffered(int16_t* aSSLVersionOffered) {
183   *aSSLVersionOffered = mTLSVersionRange.max;
184   return NS_OK;
185 }
186 
187 NS_IMETHODIMP
GetMACAlgorithmUsed(int16_t * aMac)188 nsNSSSocketInfo::GetMACAlgorithmUsed(int16_t* aMac) {
189   *aMac = mMACAlgorithmUsed;
190   return NS_OK;
191 }
192 
193 NS_IMETHODIMP
GetClientCert(nsIX509Cert ** aClientCert)194 nsNSSSocketInfo::GetClientCert(nsIX509Cert** aClientCert) {
195   NS_ENSURE_ARG_POINTER(aClientCert);
196   *aClientCert = mClientCert;
197   NS_IF_ADDREF(*aClientCert);
198   return NS_OK;
199 }
200 
201 NS_IMETHODIMP
SetClientCert(nsIX509Cert * aClientCert)202 nsNSSSocketInfo::SetClientCert(nsIX509Cert* aClientCert) {
203   mClientCert = aClientCert;
204   return NS_OK;
205 }
206 
207 NS_IMETHODIMP
GetClientCertSent(bool * arg)208 nsNSSSocketInfo::GetClientCertSent(bool* arg) {
209   *arg = mSentClientCert;
210   return NS_OK;
211 }
212 
213 NS_IMETHODIMP
GetBypassAuthentication(bool * arg)214 nsNSSSocketInfo::GetBypassAuthentication(bool* arg) {
215   *arg = mBypassAuthentication;
216   return NS_OK;
217 }
218 
219 NS_IMETHODIMP
GetFailedVerification(bool * arg)220 nsNSSSocketInfo::GetFailedVerification(bool* arg) {
221   *arg = mFailedVerification;
222   return NS_OK;
223 }
224 
225 NS_IMETHODIMP
GetRememberClientAuthCertificate(bool * aRemember)226 nsNSSSocketInfo::GetRememberClientAuthCertificate(bool* aRemember) {
227   NS_ENSURE_ARG_POINTER(aRemember);
228   *aRemember = mRememberClientAuthCertificate;
229   return NS_OK;
230 }
231 
232 NS_IMETHODIMP
SetRememberClientAuthCertificate(bool aRemember)233 nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRemember) {
234   mRememberClientAuthCertificate = aRemember;
235   return NS_OK;
236 }
237 
238 NS_IMETHODIMP
GetNotificationCallbacks(nsIInterfaceRequestor ** aCallbacks)239 nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks) {
240   *aCallbacks = mCallbacks;
241   NS_IF_ADDREF(*aCallbacks);
242   return NS_OK;
243 }
244 
245 NS_IMETHODIMP
SetNotificationCallbacks(nsIInterfaceRequestor * aCallbacks)246 nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks) {
247   if (!aCallbacks) {
248     mCallbacks = nullptr;
249     return NS_OK;
250   }
251 
252   mCallbacks = aCallbacks;
253 
254   return NS_OK;
255 }
256 
NoteTimeUntilReady()257 void nsNSSSocketInfo::NoteTimeUntilReady() {
258   if (mNotedTimeUntilReady) return;
259 
260   mNotedTimeUntilReady = true;
261 
262   // This will include TCP and proxy tunnel wait time
263   Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
264                                  mSocketCreationTimestamp, TimeStamp::Now());
265   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
266           ("[%p] nsNSSSocketInfo::NoteTimeUntilReady\n", mFd));
267 }
268 
SetHandshakeCompleted()269 void nsNSSSocketInfo::SetHandshakeCompleted() {
270   if (!mHandshakeCompleted) {
271     enum HandshakeType {
272       Resumption = 1,
273       FalseStarted = 2,
274       ChoseNotToFalseStart = 3,
275       NotAllowedToFalseStart = 4,
276     };
277 
278     HandshakeType handshakeType =
279         !IsFullHandshake() ? Resumption
280                            : mFalseStarted ? FalseStarted
281                                            : mFalseStartCallbackCalled
282                                                  ? ChoseNotToFalseStart
283                                                  : NotAllowedToFalseStart;
284 
285     // This will include TCP and proxy tunnel wait time
286     Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_HANDSHAKE_FINISHED,
287                                    mSocketCreationTimestamp, TimeStamp::Now());
288 
289     // If the handshake is completed for the first time from just 1 callback
290     // that means that TLS session resumption must have been used.
291     Telemetry::Accumulate(Telemetry::SSL_RESUMED_SESSION,
292                           handshakeType == Resumption);
293     Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_TYPE, handshakeType);
294   }
295 
296   // Remove the plaintext layer as it is not needed anymore.
297   // The plaintext layer is not always present - so it's not a fatal error if it
298   // cannot be removed.
299   // Note that PR_PopIOLayer may modify its stack, so a pointer returned by
300   // PR_GetIdentitiesLayer may not point to what we think it points to after
301   // calling PR_PopIOLayer. We must operate on the pointer returned by
302   // PR_PopIOLayer.
303   if (PR_GetIdentitiesLayer(mFd,
304                             nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) {
305     PRFileDesc* poppedPlaintext =
306         PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
307     poppedPlaintext->dtor(poppedPlaintext);
308   }
309 
310   mHandshakeCompleted = true;
311 
312   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
313           ("[%p] nsNSSSocketInfo::SetHandshakeCompleted\n", (void*)mFd));
314 
315   mIsFullHandshake = false;  // reset for next handshake on this connection
316 }
317 
SetNegotiatedNPN(const char * value,uint32_t length)318 void nsNSSSocketInfo::SetNegotiatedNPN(const char* value, uint32_t length) {
319   if (!value) {
320     mNegotiatedNPN.Truncate();
321   } else {
322     mNegotiatedNPN.Assign(value, length);
323   }
324   mNPNCompleted = true;
325 }
326 
327 NS_IMETHODIMP
GetNegotiatedNPN(nsACString & aNegotiatedNPN)328 nsNSSSocketInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN) {
329   if (!mNPNCompleted) return NS_ERROR_NOT_CONNECTED;
330 
331   aNegotiatedNPN = mNegotiatedNPN;
332   return NS_OK;
333 }
334 
335 NS_IMETHODIMP
GetAlpnEarlySelection(nsACString & aAlpnSelected)336 nsNSSSocketInfo::GetAlpnEarlySelection(nsACString& aAlpnSelected) {
337   aAlpnSelected.Truncate();
338 
339   SSLPreliminaryChannelInfo info;
340   SECStatus rv = SSL_GetPreliminaryChannelInfo(mFd, &info, sizeof(info));
341   if (rv != SECSuccess || !info.canSendEarlyData) {
342     return NS_ERROR_NOT_AVAILABLE;
343   }
344 
345   SSLNextProtoState alpnState;
346   unsigned char chosenAlpn[MAX_ALPN_LENGTH];
347   unsigned int chosenAlpnLen;
348   rv = SSL_GetNextProto(mFd, &alpnState, chosenAlpn, &chosenAlpnLen,
349                         AssertedCast<unsigned int>(ArrayLength(chosenAlpn)));
350 
351   if (rv != SECSuccess) {
352     return NS_ERROR_NOT_AVAILABLE;
353   }
354 
355   if (alpnState == SSL_NEXT_PROTO_EARLY_VALUE) {
356     aAlpnSelected.Assign(BitwiseCast<char*, unsigned char*>(chosenAlpn),
357                          chosenAlpnLen);
358   }
359 
360   return NS_OK;
361 }
362 
363 NS_IMETHODIMP
GetEarlyDataAccepted(bool * aAccepted)364 nsNSSSocketInfo::GetEarlyDataAccepted(bool* aAccepted) {
365   *aAccepted = mEarlyDataAccepted;
366   return NS_OK;
367 }
368 
SetEarlyDataAccepted(bool aAccepted)369 void nsNSSSocketInfo::SetEarlyDataAccepted(bool aAccepted) {
370   mEarlyDataAccepted = aAccepted;
371 }
372 
373 NS_IMETHODIMP
GetDenyClientCert(bool * aDenyClientCert)374 nsNSSSocketInfo::GetDenyClientCert(bool* aDenyClientCert) {
375   *aDenyClientCert = mDenyClientCert;
376   return NS_OK;
377 }
378 
379 NS_IMETHODIMP
SetDenyClientCert(bool aDenyClientCert)380 nsNSSSocketInfo::SetDenyClientCert(bool aDenyClientCert) {
381   mDenyClientCert = aDenyClientCert;
382   return NS_OK;
383 }
384 
385 NS_IMETHODIMP
DriveHandshake()386 nsNSSSocketInfo::DriveHandshake() {
387   if (!mFd) {
388     return NS_ERROR_FAILURE;
389   }
390   PRErrorCode errorCode = GetErrorCode();
391   if (errorCode) {
392     return GetXPCOMFromNSSError(errorCode);
393   }
394 
395   SECStatus rv = SSL_ForceHandshake(mFd);
396 
397   if (rv != SECSuccess) {
398     errorCode = PR_GetError();
399     if (errorCode == PR_WOULD_BLOCK_ERROR) {
400       return NS_BASE_STREAM_WOULD_BLOCK;
401     }
402 
403     SetCanceled(errorCode, SSLErrorMessageType::Plain);
404     return GetXPCOMFromNSSError(errorCode);
405   }
406   return NS_OK;
407 }
408 
409 NS_IMETHODIMP
IsAcceptableForHost(const nsACString & hostname,bool * _retval)410 nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname,
411                                      bool* _retval) {
412   NS_ENSURE_ARG(_retval);
413 
414   *_retval = false;
415 
416   // If this is the same hostname then the certicate status does not
417   // need to be considered. They are joinable.
418   if (hostname.Equals(GetHostName())) {
419     *_retval = true;
420     return NS_OK;
421   }
422 
423   // Before checking the server certificate we need to make sure the
424   // handshake has completed.
425   if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->HasServerCert()) {
426     return NS_OK;
427   }
428 
429   // If the cert has error bits (e.g. it is untrusted) then do not join.
430   // The value of mHaveCertErrorBits is only reliable because we know that
431   // the handshake completed.
432   if (SSLStatus()->mHaveCertErrorBits) return NS_OK;
433 
434   // If the connection is using client certificates then do not join
435   // because the user decides on whether to send client certs to hosts on a
436   // per-domain basis.
437   if (mSentClientCert) return NS_OK;
438 
439   // Ensure that the server certificate covers the hostname that would
440   // like to join this connection
441 
442   UniqueCERTCertificate nssCert;
443 
444   nsCOMPtr<nsIX509Cert> cert;
445   if (NS_FAILED(SSLStatus()->GetServerCert(getter_AddRefs(cert)))) {
446     return NS_OK;
447   }
448   if (cert) {
449     nssCert.reset(cert->GetCert());
450   }
451 
452   if (!nssCert) {
453     return NS_OK;
454   }
455 
456   // Attempt to verify the joinee's certificate using the joining hostname.
457   // This ensures that any hostname-specific verification logic (e.g. key
458   // pinning) is satisfied by the joinee's certificate chain.
459   // This verification only uses local information; since we're on the network
460   // thread, we would be blocking on ourselves if we attempted any network i/o.
461   // TODO(bug 1056935): The certificate chain built by this verification may be
462   // different than the certificate chain originally built during the joined
463   // connection's TLS handshake. Consequently, we may report a wrong and/or
464   // misleading certificate chain for HTTP transactions coalesced onto this
465   // connection. This may become problematic in the future. For example,
466   // if/when we begin relying on intermediate certificates being stored in the
467   // securityInfo of a cached HTTPS response, that cached certificate chain may
468   // actually be the wrong chain. We should consider having JoinConnection
469   // return the certificate chain built here, so that the calling Necko code
470   // can associate the correct certificate chain with the HTTP transactions it
471   // is trying to join onto this connection.
472   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
473   if (!certVerifier) {
474     return NS_OK;
475   }
476   CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY;
477   UniqueCERTCertList unusedBuiltChain;
478   mozilla::pkix::Result result =
479       certVerifier->VerifySSLServerCert(nssCert,
480                                         nullptr,  // stapledOCSPResponse
481                                         nullptr,  // sctsFromTLSExtension
482                                         mozilla::pkix::Now(),
483                                         nullptr,  // pinarg
484                                         hostname, unusedBuiltChain,
485                                         false,  // save intermediates
486                                         flags);
487   if (result != mozilla::pkix::Success) {
488     return NS_OK;
489   }
490 
491   // All tests pass
492   *_retval = true;
493   return NS_OK;
494 }
495 
496 NS_IMETHODIMP
TestJoinConnection(const nsACString & npnProtocol,const nsACString & hostname,int32_t port,bool * _retval)497 nsNSSSocketInfo::TestJoinConnection(const nsACString& npnProtocol,
498                                     const nsACString& hostname, int32_t port,
499                                     bool* _retval) {
500   *_retval = false;
501 
502   // Different ports may not be joined together
503   if (port != GetPort()) return NS_OK;
504 
505   // Make sure NPN has been completed and matches requested npnProtocol
506   if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol)) return NS_OK;
507 
508   if (mBypassAuthentication) {
509     // An unauthenticated connection does not know whether or not it
510     // is acceptable for a particular hostname
511     return NS_OK;
512   }
513 
514   IsAcceptableForHost(hostname, _retval);  // sets _retval
515   return NS_OK;
516 }
517 
518 NS_IMETHODIMP
JoinConnection(const nsACString & npnProtocol,const nsACString & hostname,int32_t port,bool * _retval)519 nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
520                                 const nsACString& hostname, int32_t port,
521                                 bool* _retval) {
522   nsresult rv = TestJoinConnection(npnProtocol, hostname, port, _retval);
523   if (NS_SUCCEEDED(rv) && *_retval) {
524     // All tests pass - this is joinable
525     mJoined = true;
526   }
527   return rv;
528 }
529 
GetForSTARTTLS()530 bool nsNSSSocketInfo::GetForSTARTTLS() { return mForSTARTTLS; }
531 
SetForSTARTTLS(bool aForSTARTTLS)532 void nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS) {
533   mForSTARTTLS = aForSTARTTLS;
534 }
535 
536 NS_IMETHODIMP
ProxyStartSSL()537 nsNSSSocketInfo::ProxyStartSSL() { return ActivateSSL(); }
538 
539 NS_IMETHODIMP
StartTLS()540 nsNSSSocketInfo::StartTLS() { return ActivateSSL(); }
541 
542 NS_IMETHODIMP
SetNPNList(nsTArray<nsCString> & protocolArray)543 nsNSSSocketInfo::SetNPNList(nsTArray<nsCString>& protocolArray) {
544   if (!mFd) return NS_ERROR_FAILURE;
545 
546   // the npn list is a concatenated list of 8 bit byte strings.
547   nsCString npnList;
548 
549   for (uint32_t index = 0; index < protocolArray.Length(); ++index) {
550     if (protocolArray[index].IsEmpty() || protocolArray[index].Length() > 255)
551       return NS_ERROR_ILLEGAL_VALUE;
552 
553     npnList.Append(protocolArray[index].Length());
554     npnList.Append(protocolArray[index]);
555   }
556 
557   if (SSL_SetNextProtoNego(
558           mFd, BitwiseCast<const unsigned char*, const char*>(npnList.get()),
559           npnList.Length()) != SECSuccess)
560     return NS_ERROR_FAILURE;
561 
562   return NS_OK;
563 }
564 
ActivateSSL()565 nsresult nsNSSSocketInfo::ActivateSSL() {
566   if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
567     return NS_ERROR_FAILURE;
568   if (SECSuccess != SSL_ResetHandshake(mFd, false)) return NS_ERROR_FAILURE;
569 
570   mHandshakePending = true;
571 
572   return NS_OK;
573 }
574 
GetFileDescPtr(PRFileDesc ** aFilePtr)575 nsresult nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr) {
576   *aFilePtr = mFd;
577   return NS_OK;
578 }
579 
SetFileDescPtr(PRFileDesc * aFilePtr)580 nsresult nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr) {
581   mFd = aFilePtr;
582   return NS_OK;
583 }
584 
SetCertVerificationWaiting()585 void nsNSSSocketInfo::SetCertVerificationWaiting() {
586   // mCertVerificationState may be before_cert_verification for the first
587   // handshake on the connection, or after_cert_verification for subsequent
588   // renegotiation handshakes.
589   MOZ_ASSERT(mCertVerificationState != waiting_for_cert_verification,
590              "Invalid state transition to waiting_for_cert_verification");
591   mCertVerificationState = waiting_for_cert_verification;
592 }
593 
594 // Be careful that SetCertVerificationResult does NOT get called while we are
595 // processing a SSL callback function, because SSL_AuthCertificateComplete will
596 // attempt to acquire locks that are already held by libssl when it calls
597 // callbacks.
SetCertVerificationResult(PRErrorCode errorCode,SSLErrorMessageType errorMessageType)598 void nsNSSSocketInfo::SetCertVerificationResult(
599     PRErrorCode errorCode, SSLErrorMessageType errorMessageType) {
600   MOZ_ASSERT(mCertVerificationState == waiting_for_cert_verification,
601              "Invalid state transition to cert_verification_finished");
602 
603   if (mFd) {
604     SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
605     // Only replace errorCode if there was originally no error
606     if (rv != SECSuccess && errorCode == 0) {
607       errorCode = PR_GetError();
608       errorMessageType = SSLErrorMessageType::Plain;
609       if (errorCode == 0) {
610         NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
611         errorCode = PR_INVALID_STATE_ERROR;
612       }
613     }
614   }
615 
616   if (errorCode) {
617     mFailedVerification = true;
618     SetCanceled(errorCode, errorMessageType);
619   }
620 
621   if (mPlaintextBytesRead && !errorCode) {
622     Telemetry::Accumulate(Telemetry::SSL_BYTES_BEFORE_CERT_CALLBACK,
623                           AssertedCast<uint32_t>(mPlaintextBytesRead));
624   }
625 
626   mCertVerificationState = after_cert_verification;
627 }
628 
SharedState()629 SharedSSLState& nsNSSSocketInfo::SharedState() { return mSharedState; }
630 
SetSharedOwningReference(SharedSSLState * aRef)631 void nsNSSSocketInfo::SetSharedOwningReference(SharedSSLState* aRef) {
632   mOwningSharedRef = aRef;
633 }
634 
Cleanup()635 void nsSSLIOLayerHelpers::Cleanup() {
636   MutexAutoLock lock(mutex);
637   mTLSIntoleranceInfo.Clear();
638   mInsecureFallbackSites.Clear();
639 }
640 
nsHandleSSLError(nsNSSSocketInfo * socketInfo,::mozilla::psm::SSLErrorMessageType errtype,PRErrorCode err)641 static void nsHandleSSLError(nsNSSSocketInfo* socketInfo,
642                              ::mozilla::psm::SSLErrorMessageType errtype,
643                              PRErrorCode err) {
644   if (!NS_IsMainThread()) {
645     NS_ERROR("nsHandleSSLError called off the main thread");
646     return;
647   }
648 
649   // SetCanceled is only called by the main thread or the socket transport
650   // thread. Whenever this function is called on the main thread, the SSL
651   // thread is blocked on it. So, no mutex is necessary for
652   // SetCanceled()/GetError*().
653   if (socketInfo->GetErrorCode()) {
654     // If the socket has been flagged as canceled,
655     // the code who did was responsible for setting the error code.
656     return;
657   }
658 
659   // We must cancel first, which sets the error code.
660   socketInfo->SetCanceled(err, SSLErrorMessageType::Plain);
661   nsAutoString errorString;
662   socketInfo->GetErrorLogMessage(err, errtype, errorString);
663 
664   if (!errorString.IsEmpty()) {
665     nsContentUtils::LogSimpleConsoleError(errorString, "SSL");
666   }
667 }
668 
669 namespace {
670 
671 enum Operation { reading, writing, not_reading_or_writing };
672 
673 int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
674                        PRFileDesc* ssl_layer_fd, nsNSSSocketInfo* socketInfo);
675 
getSocketInfoIfRunning(PRFileDesc * fd,Operation op)676 nsNSSSocketInfo* getSocketInfoIfRunning(PRFileDesc* fd, Operation op) {
677   if (!fd || !fd->lower || !fd->secret ||
678       fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
679     NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
680     PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
681     return nullptr;
682   }
683 
684   nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*)fd->secret;
685 
686   if (socketInfo->GetErrorCode()) {
687     PRErrorCode err = socketInfo->GetErrorCode();
688     PR_SetError(err, 0);
689     if (op == reading || op == writing) {
690       // We must do TLS intolerance checks for reads and writes, for timeouts
691       // in particular.
692       (void)checkHandshake(-1, op == reading, fd, socketInfo);
693     }
694 
695     // If we get here, it is probably because cert verification failed and this
696     // is the first I/O attempt since that failure.
697     return nullptr;
698   }
699 
700   return socketInfo;
701 }
702 
703 }  // namespace
704 
nsSSLIOLayerConnect(PRFileDesc * fd,const PRNetAddr * addr,PRIntervalTime timeout)705 static PRStatus nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
706                                     PRIntervalTime timeout) {
707   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
708           ("[%p] connecting SSL socket\n", (void*)fd));
709   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
710 
711   PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
712   if (status != PR_SUCCESS) {
713     MOZ_LOG(gPIPNSSLog, LogLevel::Error,
714             ("[%p] Lower layer connect error: %d\n", (void*)fd, PR_GetError()));
715     return status;
716   }
717 
718   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Connect\n", (void*)fd));
719   return status;
720 }
721 
rememberTolerantAtVersion(const nsACString & hostName,int16_t port,uint16_t tolerant)722 void nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName,
723                                                     int16_t port,
724                                                     uint16_t tolerant) {
725   nsCString key;
726   getSiteKey(hostName, port, key);
727 
728   MutexAutoLock lock(mutex);
729 
730   IntoleranceEntry entry;
731   if (mTLSIntoleranceInfo.Get(key, &entry)) {
732     entry.AssertInvariant();
733     entry.tolerant = std::max(entry.tolerant, tolerant);
734     if (entry.intolerant != 0 && entry.intolerant <= entry.tolerant) {
735       entry.intolerant = entry.tolerant + 1;
736       entry.intoleranceReason = 0;  // lose the reason
737     }
738   } else {
739     entry.tolerant = tolerant;
740     entry.intolerant = 0;
741     entry.intoleranceReason = 0;
742   }
743 
744   entry.AssertInvariant();
745 
746   mTLSIntoleranceInfo.Put(key, entry);
747 }
748 
forgetIntolerance(const nsACString & hostName,int16_t port)749 void nsSSLIOLayerHelpers::forgetIntolerance(const nsACString& hostName,
750                                             int16_t port) {
751   nsCString key;
752   getSiteKey(hostName, port, key);
753 
754   MutexAutoLock lock(mutex);
755 
756   IntoleranceEntry entry;
757   if (mTLSIntoleranceInfo.Get(key, &entry)) {
758     entry.AssertInvariant();
759 
760     entry.intolerant = 0;
761     entry.intoleranceReason = 0;
762 
763     entry.AssertInvariant();
764     mTLSIntoleranceInfo.Put(key, entry);
765   }
766 }
767 
fallbackLimitReached(const nsACString & hostName,uint16_t intolerant)768 bool nsSSLIOLayerHelpers::fallbackLimitReached(const nsACString& hostName,
769                                                uint16_t intolerant) {
770   if (isInsecureFallbackSite(hostName)) {
771     return intolerant <= SSL_LIBRARY_VERSION_TLS_1_0;
772   }
773   return intolerant <= mVersionFallbackLimit;
774 }
775 
776 // returns true if we should retry the handshake
rememberIntolerantAtVersion(const nsACString & hostName,int16_t port,uint16_t minVersion,uint16_t intolerant,PRErrorCode intoleranceReason)777 bool nsSSLIOLayerHelpers::rememberIntolerantAtVersion(
778     const nsACString& hostName, int16_t port, uint16_t minVersion,
779     uint16_t intolerant, PRErrorCode intoleranceReason) {
780   if (intolerant <= minVersion || fallbackLimitReached(hostName, intolerant)) {
781     // We can't fall back any further. Assume that intolerance isn't the issue.
782     forgetIntolerance(hostName, port);
783     return false;
784   }
785 
786   nsCString key;
787   getSiteKey(hostName, port, key);
788 
789   MutexAutoLock lock(mutex);
790 
791   IntoleranceEntry entry;
792   if (mTLSIntoleranceInfo.Get(key, &entry)) {
793     entry.AssertInvariant();
794     if (intolerant <= entry.tolerant) {
795       // We already know the server is tolerant at an equal or higher version.
796       return false;
797     }
798     if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
799       // We already know that the server is intolerant at a lower version.
800       return true;
801     }
802   } else {
803     entry.tolerant = 0;
804   }
805 
806   entry.intolerant = intolerant;
807   entry.intoleranceReason = intoleranceReason;
808   entry.AssertInvariant();
809   mTLSIntoleranceInfo.Put(key, entry);
810 
811   return true;
812 }
813 
adjustForTLSIntolerance(const nsACString & hostName,int16_t port,SSLVersionRange & range)814 void nsSSLIOLayerHelpers::adjustForTLSIntolerance(
815     const nsACString& hostName, int16_t port,
816     /*in/out*/ SSLVersionRange& range) {
817   IntoleranceEntry entry;
818 
819   {
820     nsCString key;
821     getSiteKey(hostName, port, key);
822 
823     MutexAutoLock lock(mutex);
824     if (!mTLSIntoleranceInfo.Get(key, &entry)) {
825       return;
826     }
827   }
828 
829   entry.AssertInvariant();
830 
831   if (entry.intolerant != 0) {
832     // We've tried connecting at a higher range but failed, so try at the
833     // version we haven't tried yet, unless we have reached the minimum.
834     if (range.min < entry.intolerant) {
835       range.max = entry.intolerant - 1;
836     }
837   }
838 }
839 
getIntoleranceReason(const nsACString & hostName,int16_t port)840 PRErrorCode nsSSLIOLayerHelpers::getIntoleranceReason(
841     const nsACString& hostName, int16_t port) {
842   IntoleranceEntry entry;
843 
844   {
845     nsCString key;
846     getSiteKey(hostName, port, key);
847 
848     MutexAutoLock lock(mutex);
849     if (!mTLSIntoleranceInfo.Get(key, &entry)) {
850       return 0;
851     }
852   }
853 
854   entry.AssertInvariant();
855   return entry.intoleranceReason;
856 }
857 
858 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
859 PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
860 PRDescIdentity nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity;
861 PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
862 PRIOMethods nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods;
863 
nsSSLIOLayerClose(PRFileDesc * fd)864 static PRStatus nsSSLIOLayerClose(PRFileDesc* fd) {
865   if (!fd) return PR_FAILURE;
866 
867   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
868           ("[%p] Shutting down socket\n", (void*)fd));
869 
870   nsNSSSocketInfo* socketInfo = (nsNSSSocketInfo*)fd->secret;
871   MOZ_ASSERT(socketInfo, "nsNSSSocketInfo was null for an fd");
872 
873   return socketInfo->CloseSocketAndDestroy();
874 }
875 
CloseSocketAndDestroy()876 PRStatus nsNSSSocketInfo::CloseSocketAndDestroy() {
877   PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
878   MOZ_ASSERT(
879       popped && popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
880       "SSL Layer not on top of stack");
881 
882   // The plaintext layer is not always present - so it's not a fatal error if it
883   // cannot be removed.
884   // Note that PR_PopIOLayer may modify its stack, so a pointer returned by
885   // PR_GetIdentitiesLayer may not point to what we think it points to after
886   // calling PR_PopIOLayer. We must operate on the pointer returned by
887   // PR_PopIOLayer.
888   if (PR_GetIdentitiesLayer(mFd,
889                             nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) {
890     PRFileDesc* poppedPlaintext =
891         PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
892     poppedPlaintext->dtor(poppedPlaintext);
893   }
894 
895   PRStatus status = mFd->methods->close(mFd);
896 
897   // the nsNSSSocketInfo instance can out-live the connection, so we need some
898   // indication that the connection has been closed. mFd == nullptr is that
899   // indication. This is needed, for example, when the connection is closed
900   // before we have finished validating the server's certificate.
901   mFd = nullptr;
902 
903   if (status != PR_SUCCESS) return status;
904 
905   popped->identity = PR_INVALID_IO_LAYER;
906   NS_RELEASE_THIS();
907   popped->dtor(popped);
908 
909   return PR_SUCCESS;
910 }
911 
912 #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
913 // Dumps a (potentially binary) buffer using SSM_DEBUG.  (We could have used
914 // the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)
915 #define DUMPBUF_LINESIZE 24
nsDumpBuffer(unsigned char * buf,int len)916 static void nsDumpBuffer(unsigned char* buf, int len) {
917   char hexbuf[DUMPBUF_LINESIZE * 3 + 1];
918   char chrbuf[DUMPBUF_LINESIZE + 1];
919   static const char* hex = "0123456789abcdef";
920   int i = 0;
921   int l = 0;
922   char ch;
923   char* c;
924   char* h;
925   if (len == 0) return;
926   hexbuf[DUMPBUF_LINESIZE * 3] = '\0';
927   chrbuf[DUMPBUF_LINESIZE] = '\0';
928   (void)memset(hexbuf, 0x20, DUMPBUF_LINESIZE * 3);
929   (void)memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
930   h = hexbuf;
931   c = chrbuf;
932 
933   while (i < len) {
934     ch = buf[i];
935 
936     if (l == DUMPBUF_LINESIZE) {
937       MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("%s%s\n", hexbuf, chrbuf));
938       (void)memset(hexbuf, 0x20, DUMPBUF_LINESIZE * 3);
939       (void)memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
940       h = hexbuf;
941       c = chrbuf;
942       l = 0;
943     }
944 
945     // Convert a character to hex.
946     *h++ = hex[(ch >> 4) & 0xf];
947     *h++ = hex[ch & 0xf];
948     h++;
949 
950     // Put the character (if it's printable) into the character buffer.
951     if ((ch >= 0x20) && (ch <= 0x7e)) {
952       *c++ = ch;
953     } else {
954       *c++ = '.';
955     }
956     i++;
957     l++;
958   }
959   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("%s%s\n", hexbuf, chrbuf));
960 }
961 
962 #define DEBUG_DUMP_BUFFER(buf, len) nsDumpBuffer(buf, len)
963 #else
964 #define DEBUG_DUMP_BUFFER(buf, len)
965 #endif
966 
967 class SSLErrorRunnable : public SyncRunnableBase {
968  public:
SSLErrorRunnable(nsNSSSocketInfo * infoObject,::mozilla::psm::SSLErrorMessageType errtype,PRErrorCode errorCode)969   SSLErrorRunnable(nsNSSSocketInfo* infoObject,
970                    ::mozilla::psm::SSLErrorMessageType errtype,
971                    PRErrorCode errorCode)
972       : mInfoObject(infoObject), mErrType(errtype), mErrorCode(errorCode) {}
973 
RunOnTargetThread()974   virtual void RunOnTargetThread() override {
975     nsHandleSSLError(mInfoObject, mErrType, mErrorCode);
976   }
977 
978   RefPtr<nsNSSSocketInfo> mInfoObject;
979   ::mozilla::psm::SSLErrorMessageType mErrType;
980   const PRErrorCode mErrorCode;
981 };
982 
983 namespace {
984 
tlsIntoleranceTelemetryBucket(PRErrorCode err)985 uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err) {
986   // returns a numeric code for where we track various errors in telemetry
987   // only errors that cause version fallback are tracked,
988   // so this is also used to determine which errors can cause version fallback
989   switch (err) {
990     case SSL_ERROR_BAD_MAC_ALERT:
991       return 1;
992     case SSL_ERROR_BAD_MAC_READ:
993       return 2;
994     case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
995       return 3;
996     case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
997       return 4;
998     case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
999       return 6;
1000     case SSL_ERROR_NO_CYPHER_OVERLAP:
1001       return 7;
1002     case SSL_ERROR_UNSUPPORTED_VERSION:
1003       return 10;
1004     case SSL_ERROR_PROTOCOL_VERSION_ALERT:
1005       return 11;
1006     case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
1007       return 13;
1008     case SSL_ERROR_DECODE_ERROR_ALERT:
1009       return 14;
1010     case PR_CONNECT_RESET_ERROR:
1011       return 16;
1012     case PR_END_OF_FILE_ERROR:
1013       return 17;
1014     case SSL_ERROR_INTERNAL_ERROR_ALERT:
1015       return 18;
1016     default:
1017       return 0;
1018   }
1019 }
1020 
retryDueToTLSIntolerance(PRErrorCode err,nsNSSSocketInfo * socketInfo)1021 bool retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo) {
1022   // This function is supposed to decide which error codes should
1023   // be used to conclude server is TLS intolerant.
1024   // Note this only happens during the initial SSL handshake.
1025 
1026   SSLVersionRange range = socketInfo->GetTLSVersionRange();
1027   nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
1028 
1029   if (err == SSL_ERROR_UNSUPPORTED_VERSION &&
1030       range.min == SSL_LIBRARY_VERSION_TLS_1_0) {
1031     socketInfo->SetSecurityState(nsIWebProgressListener::STATE_IS_INSECURE |
1032                                  nsIWebProgressListener::STATE_USES_SSL_3);
1033   }
1034 
1035   // NSS will return SSL_ERROR_RX_MALFORMED_SERVER_HELLO if anti-downgrade
1036   // detected the downgrade.
1037   if (err == SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT ||
1038       err == SSL_ERROR_RX_MALFORMED_SERVER_HELLO) {
1039     // This is a clear signal that we've fallen back too many versions.  Treat
1040     // this as a hard failure, but forget any intolerance so that later attempts
1041     // don't use this version (i.e., range.max) and trigger the error again.
1042 
1043     // First, track the original cause of the version fallback.  This uses the
1044     // same buckets as the telemetry below, except that bucket 0 will include
1045     // all cases where there wasn't an original reason.
1046     PRErrorCode originalReason = helpers.getIntoleranceReason(
1047         socketInfo->GetHostName(), socketInfo->GetPort());
1048     Telemetry::Accumulate(Telemetry::SSL_VERSION_FALLBACK_INAPPROPRIATE,
1049                           tlsIntoleranceTelemetryBucket(originalReason));
1050 
1051     helpers.forgetIntolerance(socketInfo->GetHostName(), socketInfo->GetPort());
1052 
1053     return false;
1054   }
1055 
1056   // When not using a proxy we'll see a connection reset error.
1057   // When using a proxy, we'll see an end of file error.
1058 
1059   // Don't allow STARTTLS connections to fall back on connection resets or
1060   // EOF.
1061   if ((err == PR_CONNECT_RESET_ERROR || err == PR_END_OF_FILE_ERROR) &&
1062       socketInfo->GetForSTARTTLS()) {
1063     return false;
1064   }
1065 
1066   uint32_t reason = tlsIntoleranceTelemetryBucket(err);
1067   if (reason == 0) {
1068     return false;
1069   }
1070 
1071   Telemetry::HistogramID pre;
1072   Telemetry::HistogramID post;
1073   switch (range.max) {
1074     case SSL_LIBRARY_VERSION_TLS_1_3:
1075       pre = Telemetry::SSL_TLS13_INTOLERANCE_REASON_PRE;
1076       post = Telemetry::SSL_TLS13_INTOLERANCE_REASON_POST;
1077       break;
1078     case SSL_LIBRARY_VERSION_TLS_1_2:
1079       pre = Telemetry::SSL_TLS12_INTOLERANCE_REASON_PRE;
1080       post = Telemetry::SSL_TLS12_INTOLERANCE_REASON_POST;
1081       break;
1082     case SSL_LIBRARY_VERSION_TLS_1_1:
1083       pre = Telemetry::SSL_TLS11_INTOLERANCE_REASON_PRE;
1084       post = Telemetry::SSL_TLS11_INTOLERANCE_REASON_POST;
1085       break;
1086     case SSL_LIBRARY_VERSION_TLS_1_0:
1087       pre = Telemetry::SSL_TLS10_INTOLERANCE_REASON_PRE;
1088       post = Telemetry::SSL_TLS10_INTOLERANCE_REASON_POST;
1089       break;
1090     default:
1091       MOZ_CRASH("impossible TLS version");
1092       return false;
1093   }
1094 
1095   // The difference between _PRE and _POST represents how often we avoided
1096   // TLS intolerance fallback due to remembered tolerance.
1097   Telemetry::Accumulate(pre, reason);
1098 
1099   if (!helpers.rememberIntolerantAtVersion(socketInfo->GetHostName(),
1100                                            socketInfo->GetPort(), range.min,
1101                                            range.max, err)) {
1102     return false;
1103   }
1104 
1105   Telemetry::Accumulate(post, reason);
1106 
1107   return true;
1108 }
1109 
1110 // Ensure that we haven't added too many errors to fit.
1111 static_assert((SSL_ERROR_END_OF_LIST - SSL_ERROR_BASE) <= 256,
1112               "too many SSL errors");
1113 static_assert((SEC_ERROR_END_OF_LIST - SEC_ERROR_BASE) <= 256,
1114               "too many SEC errors");
1115 static_assert((PR_MAX_ERROR - PR_NSPR_ERROR_BASE) <= 128,
1116               "too many NSPR errors");
1117 static_assert((mozilla::pkix::ERROR_BASE - mozilla::pkix::END_OF_LIST) < 31,
1118               "too many moz::pkix errors");
1119 
reportHandshakeResult(int32_t bytesTransferred,bool wasReading,PRErrorCode err)1120 static void reportHandshakeResult(int32_t bytesTransferred, bool wasReading,
1121                                   PRErrorCode err) {
1122   uint32_t bucket;
1123 
1124   // A negative bytesTransferred or a 0 read are errors.
1125   if (bytesTransferred > 0) {
1126     bucket = 0;
1127   } else if ((bytesTransferred == 0) && !wasReading) {
1128     // PR_Write() is defined to never return 0, but let's make sure.
1129     // https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/PR_Write.
1130     MOZ_ASSERT(false);
1131     bucket = 671;
1132   } else if (IS_SSL_ERROR(err)) {
1133     bucket = err - SSL_ERROR_BASE;
1134     MOZ_ASSERT(bucket > 0);  // SSL_ERROR_EXPORT_ONLY_SERVER isn't used.
1135   } else if (IS_SEC_ERROR(err)) {
1136     bucket = (err - SEC_ERROR_BASE) + 256;
1137   } else if ((err >= PR_NSPR_ERROR_BASE) && (err < PR_MAX_ERROR)) {
1138     bucket = (err - PR_NSPR_ERROR_BASE) + 512;
1139   } else if ((err >= mozilla::pkix::ERROR_BASE) &&
1140              (err < mozilla::pkix::ERROR_LIMIT)) {
1141     bucket = (err - mozilla::pkix::ERROR_BASE) + 640;
1142   } else {
1143     bucket = 671;
1144   }
1145 
1146   Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT, bucket);
1147 }
1148 
checkHandshake(int32_t bytesTransfered,bool wasReading,PRFileDesc * ssl_layer_fd,nsNSSSocketInfo * socketInfo)1149 int32_t checkHandshake(int32_t bytesTransfered, bool wasReading,
1150                        PRFileDesc* ssl_layer_fd, nsNSSSocketInfo* socketInfo) {
1151   const PRErrorCode originalError = PR_GetError();
1152   PRErrorCode err = originalError;
1153 
1154   // This is where we work around all of those SSL servers that don't
1155   // conform to the SSL spec and shutdown a connection when we request
1156   // SSL v3.1 (aka TLS).  The spec says the client says what version
1157   // of the protocol we're willing to perform, in our case SSL v3.1
1158   // In its response, the server says which version it wants to perform.
1159   // Many servers out there only know how to do v3.0.  Next, we're supposed
1160   // to send back the version of the protocol we requested (ie v3.1).  At
1161   // this point many servers's implementations are broken and they shut
1162   // down the connection when they don't see the version they sent back.
1163   // This is supposed to prevent a man in the middle from forcing one
1164   // side to dumb down to a lower level of the protocol.  Unfortunately,
1165   // there are enough broken servers out there that such a gross work-around
1166   // is necessary.  :(
1167 
1168   // Do NOT assume TLS intolerance on a closed connection after bad cert ui was
1169   // shown. Simply retry. This depends on the fact that Cert UI will not be
1170   // shown again, should the user override the bad cert.
1171 
1172   bool handleHandshakeResultNow = socketInfo->IsHandshakePending();
1173 
1174   bool wantRetry = false;
1175 
1176   if (0 > bytesTransfered) {
1177     if (handleHandshakeResultNow) {
1178       if (PR_WOULD_BLOCK_ERROR == err) {
1179         PR_SetError(err, 0);
1180         return bytesTransfered;
1181       }
1182 
1183       wantRetry = retryDueToTLSIntolerance(err, socketInfo);
1184     }
1185 
1186     // This is the common place where we trigger non-cert-errors on a SSL
1187     // socket. This might be reached at any time of the connection.
1188     //
1189     // The socketInfo->GetErrorCode() check is here to ensure we don't try to
1190     // do the synchronous dispatch to the main thread unnecessarily after we've
1191     // already handled a certificate error. (SSLErrorRunnable calls
1192     // nsHandleSSLError, which has logic to avoid replacing the error message,
1193     // so without the !socketInfo->GetErrorCode(), it would just be an
1194     // expensive no-op.)
1195     if (!wantRetry && mozilla::psm::IsNSSErrorCode(err) &&
1196         !socketInfo->GetErrorCode()) {
1197       RefPtr<SyncRunnableBase> runnable(
1198           new SSLErrorRunnable(socketInfo, SSLErrorMessageType::Plain, err));
1199       (void)runnable->DispatchToMainThreadAndWait();
1200     }
1201   } else if (wasReading && 0 == bytesTransfered) {
1202     // zero bytes on reading, socket closed
1203     if (handleHandshakeResultNow) {
1204       wantRetry = retryDueToTLSIntolerance(PR_END_OF_FILE_ERROR, socketInfo);
1205     }
1206   }
1207 
1208   if (wantRetry) {
1209     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1210             ("[%p] checkHandshake: will retry with lower max TLS version\n",
1211              ssl_layer_fd));
1212     // We want to cause the network layer to retry the connection.
1213     err = PR_CONNECT_RESET_ERROR;
1214     if (wasReading) bytesTransfered = -1;
1215   }
1216 
1217   // TLS intolerant servers only cause the first transfer to fail, so let's
1218   // set the HandshakePending attribute to false so that we don't try the logic
1219   // above again in a subsequent transfer.
1220   if (handleHandshakeResultNow) {
1221     // Report the result once for each handshake. Note that this does not
1222     // get handshakes which are cancelled before any reads or writes
1223     // happen.
1224     reportHandshakeResult(bytesTransfered, wasReading, originalError);
1225     socketInfo->SetHandshakeNotPending();
1226   }
1227 
1228   if (bytesTransfered < 0) {
1229     // Remember that we encountered an error so that getSocketInfoIfRunning
1230     // will correctly cause us to fail if another part of Gecko
1231     // (erroneously) calls an I/O function (PR_Send/PR_Recv/etc.) again on
1232     // this socket. Note that we use the original error because if we use
1233     // PR_CONNECT_RESET_ERROR, we'll repeated try to reconnect.
1234     if (originalError != PR_WOULD_BLOCK_ERROR && !socketInfo->GetErrorCode()) {
1235       socketInfo->SetCanceled(originalError, SSLErrorMessageType::Plain);
1236     }
1237     PR_SetError(err, 0);
1238   }
1239 
1240   return bytesTransfered;
1241 }
1242 
1243 }  // namespace
1244 
nsSSLIOLayerPoll(PRFileDesc * fd,int16_t in_flags,int16_t * out_flags)1245 static int16_t nsSSLIOLayerPoll(PRFileDesc* fd, int16_t in_flags,
1246                                 int16_t* out_flags) {
1247   if (!out_flags) {
1248     NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
1249     return 0;
1250   }
1251 
1252   *out_flags = 0;
1253 
1254   nsNSSSocketInfo* socketInfo =
1255       getSocketInfoIfRunning(fd, not_reading_or_writing);
1256 
1257   if (!socketInfo) {
1258     // If we get here, it is probably because certificate validation failed
1259     // and this is the first I/O operation after the failure.
1260     MOZ_LOG(
1261         gPIPNSSLog, LogLevel::Debug,
1262         ("[%p] polling SSL socket right after certificate verification failed "
1263          "or NSS shutdown or SDR logout %d\n",
1264          fd, (int)in_flags));
1265 
1266     MOZ_ASSERT(in_flags & PR_POLL_EXCEPT,
1267                "Caller did not poll for EXCEPT (canceled)");
1268     // Since this poll method cannot return errors, we want the caller to call
1269     // PR_Send/PR_Recv right away to get the error, so we tell that we are
1270     // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
1271     *out_flags = in_flags | PR_POLL_EXCEPT;  // see also bug 480619
1272     return in_flags;
1273   }
1274 
1275   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
1276           (socketInfo->IsWaitingForCertVerification()
1277                ? "[%p] polling SSL socket during certificate verification "
1278                  "using lower %d\n"
1279                : "[%p] poll SSL socket using lower %d\n",
1280            fd, (int)in_flags));
1281 
1282   // We want the handshake to continue during certificate validation, so we
1283   // don't need to do anything special here. libssl automatically blocks when
1284   // it reaches any point that would be unsafe to send/receive something before
1285   // cert validation is complete.
1286   int16_t result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
1287   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
1288           ("[%p] poll SSL socket returned %d\n", (void*)fd, (int)result));
1289   return result;
1290 }
1291 
nsSSLIOLayerHelpers(uint32_t aTlsFlags)1292 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers(uint32_t aTlsFlags)
1293     : mTreatUnsafeNegotiationAsBroken(false),
1294       mTLSIntoleranceInfo(),
1295       mVersionFallbackLimit(SSL_LIBRARY_VERSION_TLS_1_0),
1296       mutex("nsSSLIOLayerHelpers.mutex"),
1297       mTlsFlags(aTlsFlags) {}
1298 
1299 // PSMAvailable and PSMAvailable64 are reachable, but they're unimplemented in
1300 // PSM, so we set an error and return -1.
PSMAvailable(PRFileDesc *)1301 static int32_t PSMAvailable(PRFileDesc*) {
1302   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1303   return -1;
1304 }
1305 
PSMAvailable64(PRFileDesc *)1306 static int64_t PSMAvailable64(PRFileDesc*) {
1307   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1308   return -1;
1309 }
1310 
PSMGetsockname(PRFileDesc * fd,PRNetAddr * addr)1311 static PRStatus PSMGetsockname(PRFileDesc* fd, PRNetAddr* addr) {
1312   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
1313 
1314   return fd->lower->methods->getsockname(fd->lower, addr);
1315 }
1316 
PSMGetpeername(PRFileDesc * fd,PRNetAddr * addr)1317 static PRStatus PSMGetpeername(PRFileDesc* fd, PRNetAddr* addr) {
1318   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
1319 
1320   return fd->lower->methods->getpeername(fd->lower, addr);
1321 }
1322 
PSMGetsocketoption(PRFileDesc * fd,PRSocketOptionData * data)1323 static PRStatus PSMGetsocketoption(PRFileDesc* fd, PRSocketOptionData* data) {
1324   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
1325 
1326   return fd->lower->methods->getsocketoption(fd, data);
1327 }
1328 
PSMSetsocketoption(PRFileDesc * fd,const PRSocketOptionData * data)1329 static PRStatus PSMSetsocketoption(PRFileDesc* fd,
1330                                    const PRSocketOptionData* data) {
1331   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
1332 
1333   return fd->lower->methods->setsocketoption(fd, data);
1334 }
1335 
PSMRecv(PRFileDesc * fd,void * buf,int32_t amount,int flags,PRIntervalTime timeout)1336 static int32_t PSMRecv(PRFileDesc* fd, void* buf, int32_t amount, int flags,
1337                        PRIntervalTime timeout) {
1338   nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, reading);
1339   if (!socketInfo) return -1;
1340 
1341   if (flags != PR_MSG_PEEK && flags != 0) {
1342     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1343     return -1;
1344   }
1345 
1346   int32_t bytesRead =
1347       fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
1348 
1349   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
1350           ("[%p] read %d bytes\n", (void*)fd, bytesRead));
1351 
1352 #ifdef DEBUG_SSL_VERBOSE
1353   DEBUG_DUMP_BUFFER((unsigned char*)buf, bytesRead);
1354 #endif
1355 
1356   return checkHandshake(bytesRead, true, fd, socketInfo);
1357 }
1358 
PSMSend(PRFileDesc * fd,const void * buf,int32_t amount,int flags,PRIntervalTime timeout)1359 static int32_t PSMSend(PRFileDesc* fd, const void* buf, int32_t amount,
1360                        int flags, PRIntervalTime timeout) {
1361   nsNSSSocketInfo* socketInfo = getSocketInfoIfRunning(fd, writing);
1362   if (!socketInfo) return -1;
1363 
1364   if (flags != 0) {
1365     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1366     return -1;
1367   }
1368 
1369 #ifdef DEBUG_SSL_VERBOSE
1370   DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
1371 #endif
1372 
1373   if (socketInfo->IsShortWritePending() && amount > 0) {
1374   // We got "SSL short write" last time, try to flush the pending byte.
1375 #ifdef DEBUG
1376     socketInfo->CheckShortWrittenBuffer(static_cast<const unsigned char*>(buf),
1377                                         amount);
1378 #endif
1379 
1380     buf = socketInfo->GetShortWritePendingByteRef();
1381     amount = 1;
1382 
1383     MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
1384             ("[%p] pushing 1 byte after SSL short write", fd));
1385   }
1386 
1387   int32_t bytesWritten =
1388       fd->lower->methods->send(fd->lower, buf, amount, flags, timeout);
1389 
1390   // NSS indicates that it can't write all requested data (due to network
1391   // congestion, for example) by returning either one less than the amount
1392   // of data requested or 16383, if the requested amount is greater than
1393   // 16384. We refer to this as a "short write". If we simply returned
1394   // the amount that NSS did write, the layer above us would then call
1395   // PSMSend with a very small amount of data (often 1). This is inefficient
1396   // and can lead to alternating between sending large packets and very small
1397   // packets. To prevent this, we alert the layer calling us that the operation
1398   // would block and that it should be retried later, with the same data.
1399   // When it does, we tell NSS to write the remaining byte it didn't write
1400   // in the previous call. We then return the total number of bytes written,
1401   // which is the number that caused the short write plus the additional byte
1402   // we just wrote out.
1403 
1404   // The 16384 value is based on libssl's maximum buffer size:
1405   //    MAX_FRAGMENT_LENGTH - 1
1406   //
1407   // It's in a private header, though, filed bug 1394822 to expose it.
1408   static const int32_t kShortWrite16k = 16383;
1409 
1410   if ((amount > 1 && bytesWritten == (amount - 1)) ||
1411       (amount > kShortWrite16k && bytesWritten == kShortWrite16k)) {
1412     // This is indication of an "SSL short write", block to force retry.
1413     socketInfo->SetShortWritePending(
1414         bytesWritten + 1,  // The amount to return after the flush
1415         *(static_cast<const unsigned char*>(buf) + bytesWritten));
1416 
1417     MOZ_LOG(
1418         gPIPNSSLog, LogLevel::Verbose,
1419         ("[%p] indicated SSL short write for %d bytes (written just %d bytes)",
1420          fd, amount, bytesWritten));
1421 
1422     bytesWritten = -1;
1423     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
1424 
1425 #ifdef DEBUG
1426     socketInfo->RememberShortWrittenBuffer(
1427         static_cast<const unsigned char*>(buf));
1428 #endif
1429 
1430   } else if (socketInfo->IsShortWritePending() && bytesWritten == 1) {
1431     // We have now flushed all pending data in the SSL socket
1432     // after the indicated short write.  Tell the upper layer
1433     // it has sent all its data now.
1434     MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
1435             ("[%p] finished SSL short write", fd));
1436 
1437     bytesWritten = socketInfo->ResetShortWritePending();
1438   }
1439 
1440   MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
1441           ("[%p] wrote %d bytes\n", fd, bytesWritten));
1442 
1443   return checkHandshake(bytesWritten, false, fd, socketInfo);
1444 }
1445 
PSMBind(PRFileDesc * fd,const PRNetAddr * addr)1446 static PRStatus PSMBind(PRFileDesc* fd, const PRNetAddr* addr) {
1447   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) return PR_FAILURE;
1448 
1449   return fd->lower->methods->bind(fd->lower, addr);
1450 }
1451 
nsSSLIOLayerRead(PRFileDesc * fd,void * buf,int32_t amount)1452 static int32_t nsSSLIOLayerRead(PRFileDesc* fd, void* buf, int32_t amount) {
1453   return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1454 }
1455 
nsSSLIOLayerWrite(PRFileDesc * fd,const void * buf,int32_t amount)1456 static int32_t nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf,
1457                                  int32_t amount) {
1458   return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
1459 }
1460 
PSMConnectcontinue(PRFileDesc * fd,int16_t out_flags)1461 static PRStatus PSMConnectcontinue(PRFileDesc* fd, int16_t out_flags) {
1462   if (!getSocketInfoIfRunning(fd, not_reading_or_writing)) {
1463     return PR_FAILURE;
1464   }
1465 
1466   return fd->lower->methods->connectcontinue(fd, out_flags);
1467 }
1468 
1469 namespace {
1470 
1471 class PrefObserver : public nsIObserver {
1472  public:
1473   NS_DECL_THREADSAFE_ISUPPORTS
1474   NS_DECL_NSIOBSERVER
PrefObserver(nsSSLIOLayerHelpers * aOwner)1475   explicit PrefObserver(nsSSLIOLayerHelpers* aOwner) : mOwner(aOwner) {}
1476 
1477  protected:
~PrefObserver()1478   virtual ~PrefObserver() {}
1479 
1480  private:
1481   nsSSLIOLayerHelpers* mOwner;
1482 };
1483 
1484 }  // unnamed namespace
1485 
NS_IMPL_ISUPPORTS(PrefObserver,nsIObserver)1486 NS_IMPL_ISUPPORTS(PrefObserver, nsIObserver)
1487 
1488 NS_IMETHODIMP
1489 PrefObserver::Observe(nsISupports* aSubject, const char* aTopic,
1490                       const char16_t* someData) {
1491   if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
1492     NS_ConvertUTF16toUTF8 prefName(someData);
1493 
1494     if (prefName.EqualsLiteral(
1495             "security.ssl.treat_unsafe_negotiation_as_broken")) {
1496       bool enabled;
1497       Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken",
1498                            &enabled);
1499       mOwner->setTreatUnsafeNegotiationAsBroken(enabled);
1500     } else if (prefName.EqualsLiteral("security.tls.version.fallback-limit")) {
1501       mOwner->loadVersionFallbackLimit();
1502     } else if (prefName.EqualsLiteral("security.tls.insecure_fallback_hosts")) {
1503       // Changes to the whitelist on the public side will update the pref.
1504       // Don't propagate the changes to the private side.
1505       if (mOwner->isPublic()) {
1506         mOwner->initInsecureFallbackSites();
1507       }
1508     }
1509   }
1510   return NS_OK;
1511 }
1512 
PlaintextRecv(PRFileDesc * fd,void * buf,int32_t amount,int flags,PRIntervalTime timeout)1513 static int32_t PlaintextRecv(PRFileDesc* fd, void* buf, int32_t amount,
1514                              int flags, PRIntervalTime timeout) {
1515   // The shutdownlocker is not needed here because it will already be
1516   // held higher in the stack
1517   nsNSSSocketInfo* socketInfo = nullptr;
1518 
1519   int32_t bytesRead =
1520       fd->lower->methods->recv(fd->lower, buf, amount, flags, timeout);
1521   if (fd->identity == nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)
1522     socketInfo = (nsNSSSocketInfo*)fd->secret;
1523 
1524   if ((bytesRead > 0) && socketInfo)
1525     socketInfo->AddPlaintextBytesRead(bytesRead);
1526   return bytesRead;
1527 }
1528 
~nsSSLIOLayerHelpers()1529 nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers() {
1530   // mPrefObserver will only be set if this->Init was called. The GTest tests
1531   // do not call Init.
1532   if (mPrefObserver) {
1533     Preferences::RemoveObserver(
1534         mPrefObserver, "security.ssl.treat_unsafe_negotiation_as_broken");
1535     Preferences::RemoveObserver(mPrefObserver,
1536                                 "security.tls.version.fallback-limit");
1537     Preferences::RemoveObserver(mPrefObserver,
1538                                 "security.tls.insecure_fallback_hosts");
1539   }
1540 }
1541 
1542 template <typename R, R return_value, typename... Args>
InvalidPRIOMethod(Args...)1543 static R InvalidPRIOMethod(Args...) {
1544   MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
1545   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1546   return return_value;
1547 }
1548 
Init()1549 nsresult nsSSLIOLayerHelpers::Init() {
1550   if (!nsSSLIOLayerInitialized) {
1551     MOZ_ASSERT(NS_IsMainThread());
1552     nsSSLIOLayerInitialized = true;
1553     nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
1554     nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
1555 
1556     nsSSLIOLayerMethods.fsync =
1557         InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*>;
1558     nsSSLIOLayerMethods.seek =
1559         InvalidPRIOMethod<int32_t, -1, PRFileDesc*, int32_t, PRSeekWhence>;
1560     nsSSLIOLayerMethods.seek64 =
1561         InvalidPRIOMethod<int64_t, -1, PRFileDesc*, int64_t, PRSeekWhence>;
1562     nsSSLIOLayerMethods.fileInfo =
1563         InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, PRFileInfo*>;
1564     nsSSLIOLayerMethods.fileInfo64 =
1565         InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, PRFileInfo64*>;
1566     nsSSLIOLayerMethods.writev =
1567         InvalidPRIOMethod<int32_t, -1, PRFileDesc*, const PRIOVec*, int32_t,
1568                           PRIntervalTime>;
1569     nsSSLIOLayerMethods.accept =
1570         InvalidPRIOMethod<PRFileDesc*, nullptr, PRFileDesc*, PRNetAddr*,
1571                           PRIntervalTime>;
1572     nsSSLIOLayerMethods.listen =
1573         InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, int>;
1574     nsSSLIOLayerMethods.shutdown =
1575         InvalidPRIOMethod<PRStatus, PR_FAILURE, PRFileDesc*, int>;
1576     nsSSLIOLayerMethods.recvfrom =
1577         InvalidPRIOMethod<int32_t, -1, PRFileDesc*, void*, int32_t, int,
1578                           PRNetAddr*, PRIntervalTime>;
1579     nsSSLIOLayerMethods.sendto =
1580         InvalidPRIOMethod<int32_t, -1, PRFileDesc*, const void*, int32_t, int,
1581                           const PRNetAddr*, PRIntervalTime>;
1582     nsSSLIOLayerMethods.acceptread =
1583         InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRFileDesc**, PRNetAddr**,
1584                           void*, int32_t, PRIntervalTime>;
1585     nsSSLIOLayerMethods.transmitfile =
1586         InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRFileDesc*, const void*,
1587                           int32_t, PRTransmitFileFlags, PRIntervalTime>;
1588     nsSSLIOLayerMethods.sendfile =
1589         InvalidPRIOMethod<int32_t, -1, PRFileDesc*, PRSendFileData*,
1590                           PRTransmitFileFlags, PRIntervalTime>;
1591 
1592     nsSSLIOLayerMethods.available = PSMAvailable;
1593     nsSSLIOLayerMethods.available64 = PSMAvailable64;
1594     nsSSLIOLayerMethods.getsockname = PSMGetsockname;
1595     nsSSLIOLayerMethods.getpeername = PSMGetpeername;
1596     nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
1597     nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
1598     nsSSLIOLayerMethods.recv = PSMRecv;
1599     nsSSLIOLayerMethods.send = PSMSend;
1600     nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
1601     nsSSLIOLayerMethods.bind = PSMBind;
1602 
1603     nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
1604     nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
1605     nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
1606     nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
1607     nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
1608 
1609     nsSSLPlaintextLayerIdentity = PR_GetUniqueIdentity("Plaintxext PSM layer");
1610     nsSSLPlaintextLayerMethods = *PR_GetDefaultIOMethods();
1611     nsSSLPlaintextLayerMethods.recv = PlaintextRecv;
1612   }
1613 
1614   loadVersionFallbackLimit();
1615 
1616   // non main thread helpers will need to use defaults
1617   if (NS_IsMainThread()) {
1618     bool enabled = false;
1619     Preferences::GetBool("security.ssl.treat_unsafe_negotiation_as_broken",
1620                          &enabled);
1621     setTreatUnsafeNegotiationAsBroken(enabled);
1622 
1623     initInsecureFallbackSites();
1624 
1625     mPrefObserver = new PrefObserver(this);
1626     Preferences::AddStrongObserver(
1627         mPrefObserver, "security.ssl.treat_unsafe_negotiation_as_broken");
1628     Preferences::AddStrongObserver(mPrefObserver,
1629                                    "security.tls.version.fallback-limit");
1630     Preferences::AddStrongObserver(mPrefObserver,
1631                                    "security.tls.insecure_fallback_hosts");
1632   } else {
1633     MOZ_ASSERT(mTlsFlags, "Only per socket version can ignore prefs");
1634   }
1635 
1636   return NS_OK;
1637 }
1638 
loadVersionFallbackLimit()1639 void nsSSLIOLayerHelpers::loadVersionFallbackLimit() {
1640   // see nsNSSComponent::setEnabledTLSVersions for pref handling rules
1641   uint32_t limit = 3;  // TLS 1.2
1642 
1643   if (NS_IsMainThread()) {
1644     limit = Preferences::GetUint("security.tls.version.fallback-limit",
1645                                  3);  // 3 = TLS 1.2
1646   }
1647 
1648   // set fallback limit if it is set in the tls flags
1649   uint32_t tlsFlagsFallbackLimit = getTLSProviderFlagFallbackLimit(mTlsFlags);
1650 
1651   if (tlsFlagsFallbackLimit) {
1652     limit = tlsFlagsFallbackLimit;
1653     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1654             ("loadVersionFallbackLimit overriden by tlsFlags %d\n", limit));
1655   }
1656 
1657   SSLVersionRange defaults = {SSL_LIBRARY_VERSION_TLS_1_2,
1658                               SSL_LIBRARY_VERSION_TLS_1_2};
1659   SSLVersionRange filledInRange;
1660   nsNSSComponent::FillTLSVersionRange(filledInRange, limit, limit, defaults);
1661   if (filledInRange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
1662     filledInRange.max = SSL_LIBRARY_VERSION_TLS_1_2;
1663   }
1664 
1665   mVersionFallbackLimit = filledInRange.max;
1666 }
1667 
clearStoredData()1668 void nsSSLIOLayerHelpers::clearStoredData() {
1669   MutexAutoLock lock(mutex);
1670   mInsecureFallbackSites.Clear();
1671   mTLSIntoleranceInfo.Clear();
1672 }
1673 
setInsecureFallbackSites(const nsCString & str)1674 void nsSSLIOLayerHelpers::setInsecureFallbackSites(const nsCString& str) {
1675   MutexAutoLock lock(mutex);
1676 
1677   mInsecureFallbackSites.Clear();
1678 
1679   if (str.IsEmpty()) {
1680     return;
1681   }
1682 
1683   nsCCharSeparatedTokenizer toker(str, ',');
1684 
1685   while (toker.hasMoreTokens()) {
1686     const nsACString& host = toker.nextToken();
1687     if (!host.IsEmpty()) {
1688       mInsecureFallbackSites.PutEntry(host);
1689     }
1690   }
1691 }
1692 
initInsecureFallbackSites()1693 void nsSSLIOLayerHelpers::initInsecureFallbackSites() {
1694   MOZ_ASSERT(NS_IsMainThread());
1695   nsAutoCString insecureFallbackHosts;
1696   Preferences::GetCString("security.tls.insecure_fallback_hosts",
1697                           insecureFallbackHosts);
1698   setInsecureFallbackSites(insecureFallbackHosts);
1699 }
1700 
isPublic() const1701 bool nsSSLIOLayerHelpers::isPublic() const {
1702   return this == &PublicSSLState()->IOLayerHelpers();
1703 }
1704 
1705 class FallbackPrefRemover final : public Runnable {
1706  public:
FallbackPrefRemover(const nsACString & aHost)1707   explicit FallbackPrefRemover(const nsACString& aHost)
1708       : mozilla::Runnable("FallbackPrefRemover"), mHost(aHost) {}
1709   NS_IMETHOD Run() override;
1710 
1711  private:
1712   nsCString mHost;
1713 };
1714 
1715 NS_IMETHODIMP
Run()1716 FallbackPrefRemover::Run() {
1717   MOZ_ASSERT(NS_IsMainThread());
1718   nsAutoCString oldValue;
1719   Preferences::GetCString("security.tls.insecure_fallback_hosts", oldValue);
1720   nsCCharSeparatedTokenizer toker(oldValue, ',');
1721   nsCString newValue;
1722   while (toker.hasMoreTokens()) {
1723     const nsACString& host = toker.nextToken();
1724     if (host.Equals(mHost)) {
1725       continue;
1726     }
1727     if (!newValue.IsEmpty()) {
1728       newValue.Append(',');
1729     }
1730     newValue.Append(host);
1731   }
1732   Preferences::SetCString("security.tls.insecure_fallback_hosts", newValue);
1733   return NS_OK;
1734 }
1735 
removeInsecureFallbackSite(const nsACString & hostname,uint16_t port)1736 void nsSSLIOLayerHelpers::removeInsecureFallbackSite(const nsACString& hostname,
1737                                                      uint16_t port) {
1738   forgetIntolerance(hostname, port);
1739   {
1740     MutexAutoLock lock(mutex);
1741     if (!mInsecureFallbackSites.Contains(hostname)) {
1742       return;
1743     }
1744     mInsecureFallbackSites.RemoveEntry(hostname);
1745   }
1746   if (!isPublic()) {
1747     return;
1748   }
1749   RefPtr<Runnable> runnable = new FallbackPrefRemover(hostname);
1750   if (NS_IsMainThread()) {
1751     runnable->Run();
1752   } else {
1753     NS_DispatchToMainThread(runnable);
1754   }
1755 }
1756 
isInsecureFallbackSite(const nsACString & hostname)1757 bool nsSSLIOLayerHelpers::isInsecureFallbackSite(const nsACString& hostname) {
1758   MutexAutoLock lock(mutex);
1759   return mInsecureFallbackSites.Contains(hostname);
1760 }
1761 
setTreatUnsafeNegotiationAsBroken(bool broken)1762 void nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken) {
1763   MutexAutoLock lock(mutex);
1764   mTreatUnsafeNegotiationAsBroken = broken;
1765 }
1766 
treatUnsafeNegotiationAsBroken()1767 bool nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken() {
1768   MutexAutoLock lock(mutex);
1769   return mTreatUnsafeNegotiationAsBroken;
1770 }
1771 
nsSSLIOLayerNewSocket(int32_t family,const char * host,int32_t port,nsIProxyInfo * proxy,const OriginAttributes & originAttributes,PRFileDesc ** fd,nsISupports ** info,bool forSTARTTLS,uint32_t flags,uint32_t tlsFlags)1772 nsresult nsSSLIOLayerNewSocket(int32_t family, const char* host, int32_t port,
1773                                nsIProxyInfo* proxy,
1774                                const OriginAttributes& originAttributes,
1775                                PRFileDesc** fd, nsISupports** info,
1776                                bool forSTARTTLS, uint32_t flags,
1777                                uint32_t tlsFlags) {
1778   PRFileDesc* sock = PR_OpenTCPSocket(family);
1779   if (!sock) return NS_ERROR_OUT_OF_MEMORY;
1780 
1781   nsresult rv =
1782       nsSSLIOLayerAddToSocket(family, host, port, proxy, originAttributes, sock,
1783                               info, forSTARTTLS, flags, tlsFlags);
1784   if (NS_FAILED(rv)) {
1785     PR_Close(sock);
1786     return rv;
1787   }
1788 
1789   *fd = sock;
1790   return NS_OK;
1791 }
1792 
1793 // Creates CA names strings from (CERTDistNames* caNames)
1794 //
1795 // - arena: arena to allocate strings on
1796 // - caNameStrings: filled with CA names strings on return
1797 // - caNames: CERTDistNames to extract strings from
1798 // - return: SECSuccess if successful; error code otherwise
1799 //
1800 // Note: copied in its entirety from Nova code
nsConvertCANamesToStrings(const UniquePLArenaPool & arena,char ** caNameStrings,CERTDistNames * caNames)1801 static SECStatus nsConvertCANamesToStrings(const UniquePLArenaPool& arena,
1802                                            char** caNameStrings,
1803                                            CERTDistNames* caNames) {
1804   MOZ_ASSERT(arena.get());
1805   MOZ_ASSERT(caNameStrings);
1806   MOZ_ASSERT(caNames);
1807   if (!arena.get() || !caNameStrings || !caNames) {
1808     PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
1809     return SECFailure;
1810   }
1811 
1812   SECItem* dername;
1813   SECStatus rv;
1814   int headerlen;
1815   uint32_t contentlen;
1816   SECItem newitem;
1817   int n;
1818   char* namestring;
1819 
1820   for (n = 0; n < caNames->nnames; n++) {
1821     newitem.data = nullptr;
1822     dername = &caNames->names[n];
1823 
1824     rv = DER_Lengths(dername, &headerlen, &contentlen);
1825 
1826     if (rv != SECSuccess) {
1827       goto loser;
1828     }
1829 
1830     if (headerlen + contentlen != dername->len) {
1831       // This must be from an enterprise 2.x server, which sent
1832       // incorrectly formatted der without the outer wrapper of type and
1833       // length. Fix it up by adding the top level header.
1834       if (dername->len <= 127) {
1835         newitem.data = (unsigned char*)malloc(dername->len + 2);
1836         if (!newitem.data) {
1837           goto loser;
1838         }
1839         newitem.data[0] = (unsigned char)0x30;
1840         newitem.data[1] = (unsigned char)dername->len;
1841         (void)memcpy(&newitem.data[2], dername->data, dername->len);
1842       } else if (dername->len <= 255) {
1843         newitem.data = (unsigned char*)malloc(dername->len + 3);
1844         if (!newitem.data) {
1845           goto loser;
1846         }
1847         newitem.data[0] = (unsigned char)0x30;
1848         newitem.data[1] = (unsigned char)0x81;
1849         newitem.data[2] = (unsigned char)dername->len;
1850         (void)memcpy(&newitem.data[3], dername->data, dername->len);
1851       } else {
1852         // greater than 256, better be less than 64k
1853         newitem.data = (unsigned char*)malloc(dername->len + 4);
1854         if (!newitem.data) {
1855           goto loser;
1856         }
1857         newitem.data[0] = (unsigned char)0x30;
1858         newitem.data[1] = (unsigned char)0x82;
1859         newitem.data[2] = (unsigned char)((dername->len >> 8) & 0xff);
1860         newitem.data[3] = (unsigned char)(dername->len & 0xff);
1861         memcpy(&newitem.data[4], dername->data, dername->len);
1862       }
1863       dername = &newitem;
1864     }
1865 
1866     namestring = CERT_DerNameToAscii(dername);
1867     if (!namestring) {
1868       // XXX - keep going until we fail to convert the name
1869       caNameStrings[n] = const_cast<char*>("");
1870     } else {
1871       caNameStrings[n] = PORT_ArenaStrdup(arena.get(), namestring);
1872       PR_Free(namestring);  // CERT_DerNameToAscii() uses PR_Malloc().
1873       if (!caNameStrings[n]) {
1874         goto loser;
1875       }
1876     }
1877 
1878     if (newitem.data) {
1879       free(newitem.data);
1880     }
1881   }
1882 
1883   return SECSuccess;
1884 loser:
1885   if (newitem.data) {
1886     free(newitem.data);
1887   }
1888   return SECFailure;
1889 }
1890 
1891 // Possible behaviors for choosing a cert for client auth.
1892 enum class UserCertChoice {
1893   // Ask the user to choose a cert.
1894   Ask = 0,
1895   // Automatically choose a cert.
1896   Auto = 1,
1897 };
1898 
1899 // Returns the most appropriate user cert choice based on the value of the
1900 // security.default_personal_cert preference.
nsGetUserCertChoice()1901 UserCertChoice nsGetUserCertChoice() {
1902   nsAutoCString value;
1903   nsresult rv =
1904       Preferences::GetCString("security.default_personal_cert", value);
1905   if (NS_FAILED(rv)) {
1906     return UserCertChoice::Ask;
1907   }
1908 
1909   // There are three cases for what the preference could be set to:
1910   //   1. "Select Automatically" -> Auto.
1911   //   2. "Ask Every Time" -> Ask.
1912   //   3. Something else -> Ask. This might be a nickname from a migrated cert,
1913   //      but we no longer support this case.
1914   return value.EqualsLiteral("Select Automatically") ? UserCertChoice::Auto
1915                                                      : UserCertChoice::Ask;
1916 }
1917 
hasExplicitKeyUsageNonRepudiation(CERTCertificate * cert)1918 static bool hasExplicitKeyUsageNonRepudiation(CERTCertificate* cert) {
1919   // There is no extension, v1 or v2 certificate
1920   if (!cert->extensions) return false;
1921 
1922   SECStatus srv;
1923   SECItem keyUsageItem;
1924   keyUsageItem.data = nullptr;
1925 
1926   srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
1927   if (srv == SECFailure) return false;
1928 
1929   unsigned char keyUsage = keyUsageItem.data[0];
1930   PORT_Free(keyUsageItem.data);
1931 
1932   return !!(keyUsage & KU_NON_REPUDIATION);
1933 }
1934 
1935 class ClientAuthDataRunnable : public SyncRunnableBase {
1936  public:
ClientAuthDataRunnable(CERTDistNames * caNames,CERTCertificate ** pRetCert,SECKEYPrivateKey ** pRetKey,nsNSSSocketInfo * info,const UniqueCERTCertificate & serverCert)1937   ClientAuthDataRunnable(CERTDistNames* caNames, CERTCertificate** pRetCert,
1938                          SECKEYPrivateKey** pRetKey, nsNSSSocketInfo* info,
1939                          const UniqueCERTCertificate& serverCert)
1940       : mRV(SECFailure),
1941         mErrorCodeToReport(SEC_ERROR_NO_MEMORY),
1942         mPRetCert(pRetCert),
1943         mPRetKey(pRetKey),
1944         mCANames(caNames),
1945         mSocketInfo(info),
1946         mServerCert(serverCert.get()) {}
1947 
1948   SECStatus mRV;                      // out
1949   PRErrorCode mErrorCodeToReport;     // out
1950   CERTCertificate** const mPRetCert;  // in/out
1951   SECKEYPrivateKey** const mPRetKey;  // in/out
1952  protected:
1953   virtual void RunOnTargetThread() override;
1954 
1955  private:
1956   CERTDistNames* const mCANames;       // in
1957   nsNSSSocketInfo* const mSocketInfo;  // in
1958   CERTCertificate* const mServerCert;  // in
1959 };
1960 
1961 // This callback function is used to pull client certificate
1962 // information upon server request
1963 //
1964 // - arg: SSL data connection
1965 // - socket: SSL socket we're dealing with
1966 // - caNames: list of CA names
1967 // - pRetCert: returns a pointer to a pointer to a valid certificate if
1968 //             successful; otherwise nullptr
1969 // - pRetKey: returns a pointer to a pointer to the corresponding key if
1970 //            successful; otherwise nullptr
nsNSS_SSLGetClientAuthData(void * arg,PRFileDesc * socket,CERTDistNames * caNames,CERTCertificate ** pRetCert,SECKEYPrivateKey ** pRetKey)1971 SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
1972                                      CERTDistNames* caNames,
1973                                      CERTCertificate** pRetCert,
1974                                      SECKEYPrivateKey** pRetKey) {
1975   if (!socket || !caNames || !pRetCert || !pRetKey) {
1976     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1977     return SECFailure;
1978   }
1979 
1980   RefPtr<nsNSSSocketInfo> info(
1981       BitwiseCast<nsNSSSocketInfo*, PRFilePrivate*>(socket->higher->secret));
1982 
1983   UniqueCERTCertificate serverCert(SSL_PeerCertificate(socket));
1984   if (!serverCert) {
1985     MOZ_ASSERT_UNREACHABLE(
1986         "Missing server cert should have been detected during server cert "
1987         "auth.");
1988     PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
1989     return SECFailure;
1990   }
1991 
1992   if (info->GetDenyClientCert()) {
1993     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1994             ("[%p] Not returning client cert due to denyClientCert attribute\n",
1995              socket));
1996     *pRetCert = nullptr;
1997     *pRetKey = nullptr;
1998     return SECSuccess;
1999   }
2000 
2001   if (info->GetJoined()) {
2002     // We refuse to send a client certificate when there are multiple hostnames
2003     // joined on this connection, because we only show the user one hostname
2004     // (mHostName) in the client certificate UI.
2005 
2006     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2007             ("[%p] Not returning client cert due to previous join\n", socket));
2008     *pRetCert = nullptr;
2009     *pRetKey = nullptr;
2010     return SECSuccess;
2011   }
2012 
2013   // XXX: This should be done asynchronously; see bug 696976
2014   RefPtr<ClientAuthDataRunnable> runnable(
2015       new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert));
2016   nsresult rv = runnable->DispatchToMainThreadAndWait();
2017   if (NS_FAILED(rv)) {
2018     PR_SetError(SEC_ERROR_NO_MEMORY, 0);
2019     return SECFailure;
2020   }
2021 
2022   if (runnable->mRV != SECSuccess) {
2023     PR_SetError(runnable->mErrorCodeToReport, 0);
2024   } else if (*runnable->mPRetCert || *runnable->mPRetKey) {
2025     // Make joinConnection prohibit joining after we've sent a client cert
2026     info->SetSentClientCert();
2027   }
2028 
2029   return runnable->mRV;
2030 }
2031 
RunOnTargetThread()2032 void ClientAuthDataRunnable::RunOnTargetThread() {
2033   // We check the value of a pref in this runnable, so this runnable should only
2034   // be run on the main thread.
2035   MOZ_ASSERT(NS_IsMainThread());
2036 
2037   UniquePLArenaPool arena;
2038   char** caNameStrings;
2039   UniqueCERTCertificate cert;
2040   UniqueSECKEYPrivateKey privKey;
2041   void* wincx = mSocketInfo;
2042   nsresult rv;
2043 
2044   if (NS_FAILED(CheckForSmartCardChanges())) {
2045     mRV = SECFailure;
2046     *mPRetCert = nullptr;
2047     *mPRetKey = nullptr;
2048     mErrorCodeToReport = SEC_ERROR_LIBRARY_FAILURE;
2049     return;
2050   }
2051 
2052   nsCOMPtr<nsIX509Cert> socketClientCert;
2053   mSocketInfo->GetClientCert(getter_AddRefs(socketClientCert));
2054 
2055   // If a client cert preference was set on the socket info, use that and skip
2056   // the client cert UI and/or search of the user's past cert decisions.
2057   if (socketClientCert) {
2058     cert.reset(socketClientCert->GetCert());
2059     if (!cert) {
2060       goto loser;
2061     }
2062 
2063     // Get the private key
2064     privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
2065     if (!privKey) {
2066       goto loser;
2067     }
2068 
2069     *mPRetCert = cert.release();
2070     *mPRetKey = privKey.release();
2071     mRV = SECSuccess;
2072     return;
2073   }
2074 
2075   // create caNameStrings
2076   arena.reset(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
2077   if (!arena) {
2078     goto loser;
2079   }
2080 
2081   caNameStrings = static_cast<char**>(
2082       PORT_ArenaAlloc(arena.get(), sizeof(char*) * mCANames->nnames));
2083   if (!caNameStrings) {
2084     goto loser;
2085   }
2086 
2087   mRV = nsConvertCANamesToStrings(arena, caNameStrings, mCANames);
2088   if (mRV != SECSuccess) {
2089     goto loser;
2090   }
2091 
2092   // find valid user cert and key pair
2093   if (nsGetUserCertChoice() == UserCertChoice::Auto) {
2094     // automatically find the right cert
2095 
2096     // find all user certs that are valid and for SSL
2097     UniqueCERTCertList certList(CERT_FindUserCertsByUsage(
2098         CERT_GetDefaultCertDB(), certUsageSSLClient, false, true, wincx));
2099     if (!certList) {
2100       goto loser;
2101     }
2102 
2103     // filter the list to those issued by CAs supported by the server
2104     mRV = CERT_FilterCertListByCANames(certList.get(), mCANames->nnames,
2105                                        caNameStrings, certUsageSSLClient);
2106     if (mRV != SECSuccess) {
2107       goto loser;
2108     }
2109 
2110     // make sure the list is not empty
2111     if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
2112       goto loser;
2113     }
2114 
2115     UniqueCERTCertificate lowPrioNonrepCert;
2116 
2117     // loop through the list until we find a cert with a key
2118     for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
2119          !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) {
2120       // if the certificate has restriction and we do not satisfy it we do not
2121       // use it
2122       privKey.reset(PK11_FindKeyByAnyCert(node->cert, wincx));
2123       if (privKey) {
2124         if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
2125           privKey = nullptr;
2126           // Not a preferred cert
2127           if (!lowPrioNonrepCert) {  // did not yet find a low prio cert
2128             lowPrioNonrepCert.reset(CERT_DupCertificate(node->cert));
2129           }
2130         } else {
2131           // this is a good cert to present
2132           cert.reset(CERT_DupCertificate(node->cert));
2133           break;
2134         }
2135       }
2136       if (PR_GetError() == SEC_ERROR_BAD_PASSWORD) {
2137         // problem with password: bail
2138         goto loser;
2139       }
2140     }
2141 
2142     if (!cert && lowPrioNonrepCert) {
2143       cert = Move(lowPrioNonrepCert);
2144       privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
2145     }
2146 
2147     if (!cert) {
2148       goto loser;
2149     }
2150   } else {  // Not Auto => ask
2151     // Get the SSL Certificate
2152 
2153     const nsACString& hostname = mSocketInfo->GetHostName();
2154 
2155     RefPtr<nsClientAuthRememberService> cars =
2156         mSocketInfo->SharedState().GetClientAuthRememberService();
2157 
2158     bool hasRemembered = false;
2159     nsCString rememberedDBKey;
2160     if (cars) {
2161       bool found;
2162       rv = cars->HasRememberedDecision(hostname,
2163                                        mSocketInfo->GetOriginAttributes(),
2164                                        mServerCert, rememberedDBKey, &found);
2165       if (NS_SUCCEEDED(rv) && found) {
2166         hasRemembered = true;
2167       }
2168     }
2169 
2170     if (hasRemembered && !rememberedDBKey.IsEmpty()) {
2171       nsCOMPtr<nsIX509CertDB> certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
2172       if (certdb) {
2173         nsCOMPtr<nsIX509Cert> foundCert;
2174         rv =
2175             certdb->FindCertByDBKey(rememberedDBKey, getter_AddRefs(foundCert));
2176         if (NS_SUCCEEDED(rv) && foundCert) {
2177           nsNSSCertificate* objCert =
2178               BitwiseCast<nsNSSCertificate*, nsIX509Cert*>(foundCert.get());
2179           if (objCert) {
2180             cert.reset(objCert->GetCert());
2181           }
2182         }
2183 
2184         if (!cert) {
2185           hasRemembered = false;
2186         }
2187       }
2188     }
2189 
2190     if (!hasRemembered) {
2191       // user selects a cert to present
2192       nsCOMPtr<nsIClientAuthDialogs> dialogs;
2193 
2194       // find all user certs that are for SSL
2195       // note that we are allowing expired certs in this list
2196       UniqueCERTCertList certList(CERT_FindUserCertsByUsage(
2197           CERT_GetDefaultCertDB(), certUsageSSLClient, false, false, wincx));
2198       if (!certList) {
2199         goto loser;
2200       }
2201 
2202       if (mCANames->nnames != 0) {
2203         // filter the list to those issued by CAs supported by the server
2204         mRV = CERT_FilterCertListByCANames(certList.get(), mCANames->nnames,
2205                                            caNameStrings, certUsageSSLClient);
2206         if (mRV != SECSuccess) {
2207           goto loser;
2208         }
2209       }
2210 
2211       if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
2212         // list is empty - no matching certs
2213         goto loser;
2214       }
2215 
2216       UniquePORTString corg(CERT_GetOrgName(&mServerCert->subject));
2217       nsAutoCString org(corg.get());
2218 
2219       UniquePORTString cissuer(CERT_GetOrgName(&mServerCert->issuer));
2220       nsAutoCString issuer(cissuer.get());
2221 
2222       nsCOMPtr<nsIMutableArray> certArray = nsArrayBase::Create();
2223       if (!certArray) {
2224         goto loser;
2225       }
2226 
2227       for (CERTCertListNode* node = CERT_LIST_HEAD(certList);
2228            !CERT_LIST_END(node, certList); node = CERT_LIST_NEXT(node)) {
2229         nsCOMPtr<nsIX509Cert> tempCert = nsNSSCertificate::Create(node->cert);
2230         if (!tempCert) {
2231           goto loser;
2232         }
2233 
2234         rv = certArray->AppendElement(tempCert);
2235         if (NS_FAILED(rv)) {
2236           goto loser;
2237         }
2238       }
2239 
2240       // Throw up the client auth dialog and get back the index of the selected
2241       // cert
2242       rv = getNSSDialogs(getter_AddRefs(dialogs),
2243                          NS_GET_IID(nsIClientAuthDialogs),
2244                          NS_CLIENTAUTHDIALOGS_CONTRACTID);
2245 
2246       if (NS_FAILED(rv)) {
2247         goto loser;
2248       }
2249 
2250       uint32_t selectedIndex = 0;
2251       bool certChosen = false;
2252       rv = dialogs->ChooseCertificate(mSocketInfo, hostname,
2253                                       mSocketInfo->GetPort(), org, issuer,
2254                                       certArray, &selectedIndex, &certChosen);
2255       if (NS_FAILED(rv)) {
2256         goto loser;
2257       }
2258 
2259       // even if the user has canceled, we want to remember that, to avoid
2260       // repeating prompts
2261       bool wantRemember = false;
2262       mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
2263 
2264       if (certChosen) {
2265         nsCOMPtr<nsIX509Cert> selectedCert =
2266             do_QueryElementAt(certArray, selectedIndex);
2267         if (!selectedCert) {
2268           goto loser;
2269         }
2270         cert.reset(selectedCert->GetCert());
2271       }
2272 
2273       if (cars && wantRemember) {
2274         cars->RememberDecision(hostname, mSocketInfo->GetOriginAttributes(),
2275                                mServerCert, certChosen ? cert.get() : nullptr);
2276       }
2277     }
2278 
2279     if (!cert) {
2280       goto loser;
2281     }
2282 
2283     // go get the private key
2284     privKey.reset(PK11_FindKeyByAnyCert(cert.get(), wincx));
2285     if (!privKey) {
2286       goto loser;
2287     }
2288   }
2289   goto done;
2290 
2291 loser:
2292   if (mRV == SECSuccess) {
2293     mRV = SECFailure;
2294   }
2295 done:
2296   int error = PR_GetError();
2297 
2298   *mPRetCert = cert.release();
2299   *mPRetKey = privKey.release();
2300 
2301   if (mRV == SECFailure) {
2302     mErrorCodeToReport = error;
2303   }
2304 }
2305 
nsSSLIOLayerImportFD(PRFileDesc * fd,nsNSSSocketInfo * infoObject,const char * host)2306 static PRFileDesc* nsSSLIOLayerImportFD(PRFileDesc* fd,
2307                                         nsNSSSocketInfo* infoObject,
2308                                         const char* host) {
2309   PRFileDesc* sslSock = SSL_ImportFD(nullptr, fd);
2310   if (!sslSock) {
2311     MOZ_ASSERT_UNREACHABLE("NSS: Error importing socket");
2312     return nullptr;
2313   }
2314   SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
2315   SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
2316   SSL_SetCanFalseStartCallback(sslSock, CanFalseStartCallback, infoObject);
2317 
2318   // Disable this hook if we connect anonymously. See bug 466080.
2319   uint32_t flags = 0;
2320   infoObject->GetProviderFlags(&flags);
2321   if (flags & nsISocketProvider::ANONYMOUS_CONNECT) {
2322     SSL_GetClientAuthDataHook(sslSock, nullptr, infoObject);
2323   } else {
2324     SSL_GetClientAuthDataHook(
2325         sslSock, (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData, infoObject);
2326   }
2327   if (flags & nsISocketProvider::MITM_OK) {
2328     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2329             ("[%p] nsSSLIOLayerImportFD: bypass authentication flag\n", fd));
2330     infoObject->SetBypassAuthentication(true);
2331   }
2332   if (SECSuccess !=
2333       SSL_AuthCertificateHook(sslSock, AuthCertificateHook, infoObject)) {
2334     MOZ_ASSERT_UNREACHABLE("Failed to configure AuthCertificateHook");
2335     goto loser;
2336   }
2337 
2338   if (SECSuccess != SSL_SetURL(sslSock, host)) {
2339     MOZ_ASSERT_UNREACHABLE("SSL_SetURL failed");
2340     goto loser;
2341   }
2342 
2343   return sslSock;
2344 loser:
2345   if (sslSock) {
2346     PR_Close(sslSock);
2347   }
2348   return nullptr;
2349 }
2350 
2351 // Please change getSignatureName in nsNSSCallbacks.cpp when changing the list
2352 // here.
2353 static const SSLSignatureScheme sEnabledSignatureSchemes[] = {
2354     ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384,
2355     ssl_sig_ecdsa_secp521r1_sha512, ssl_sig_rsa_pss_sha256,
2356     ssl_sig_rsa_pss_sha384,         ssl_sig_rsa_pss_sha512,
2357     ssl_sig_rsa_pkcs1_sha256,       ssl_sig_rsa_pkcs1_sha384,
2358     ssl_sig_rsa_pkcs1_sha512,       ssl_sig_ecdsa_sha1,
2359     ssl_sig_rsa_pkcs1_sha1,
2360 };
2361 
nsSSLIOLayerSetOptions(PRFileDesc * fd,bool forSTARTTLS,bool haveProxy,const char * host,int32_t port,nsNSSSocketInfo * infoObject)2362 static nsresult nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
2363                                        bool haveProxy, const char* host,
2364                                        int32_t port,
2365                                        nsNSSSocketInfo* infoObject) {
2366   if (forSTARTTLS || haveProxy) {
2367     if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
2368       return NS_ERROR_FAILURE;
2369     }
2370   }
2371 
2372   SSLVersionRange range;
2373   if (SSL_VersionRangeGet(fd, &range) != SECSuccess) {
2374     return NS_ERROR_FAILURE;
2375   }
2376 
2377   // Set TLS 1.3 compat mode.
2378   if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS13_COMPAT_MODE, PR_TRUE)) {
2379     MOZ_LOG(gPIPNSSLog, LogLevel::Error,
2380             ("[%p] nsSSLIOLayerSetOptions: Setting compat mode failed\n", fd));
2381   }
2382 
2383   // setting TLS max version
2384   uint32_t versionFlags =
2385       getTLSProviderFlagMaxVersion(infoObject->GetProviderTlsFlags());
2386   if (versionFlags) {
2387     MOZ_LOG(
2388         gPIPNSSLog, LogLevel::Debug,
2389         ("[%p] nsSSLIOLayerSetOptions: version flags %d\n", fd, versionFlags));
2390     if (versionFlags == kTLSProviderFlagMaxVersion10) {
2391       range.max = SSL_LIBRARY_VERSION_TLS_1_0;
2392     } else if (versionFlags == kTLSProviderFlagMaxVersion11) {
2393       range.max = SSL_LIBRARY_VERSION_TLS_1_1;
2394     } else if (versionFlags == kTLSProviderFlagMaxVersion12) {
2395       range.max = SSL_LIBRARY_VERSION_TLS_1_2;
2396     } else if (versionFlags == kTLSProviderFlagMaxVersion13) {
2397       range.max = SSL_LIBRARY_VERSION_TLS_1_3;
2398     } else {
2399       MOZ_LOG(gPIPNSSLog, LogLevel::Error,
2400               ("[%p] nsSSLIOLayerSetOptions: unknown version flags %d\n", fd,
2401                versionFlags));
2402     }
2403   }
2404 
2405   if ((infoObject->GetProviderFlags() & nsISocketProvider::BE_CONSERVATIVE) &&
2406       (range.max > SSL_LIBRARY_VERSION_TLS_1_2)) {
2407     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2408             ("[%p] nsSSLIOLayerSetOptions: range.max limited to 1.2 due to "
2409              "BE_CONSERVATIVE flag\n",
2410              fd));
2411     range.max = SSL_LIBRARY_VERSION_TLS_1_2;
2412   }
2413 
2414   uint16_t maxEnabledVersion = range.max;
2415   infoObject->SharedState().IOLayerHelpers().adjustForTLSIntolerance(
2416       infoObject->GetHostName(), infoObject->GetPort(), range);
2417   MOZ_LOG(
2418       gPIPNSSLog, LogLevel::Debug,
2419       ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
2420        fd, static_cast<unsigned int>(range.min),
2421        static_cast<unsigned int>(range.max)));
2422 
2423   // If the user has set their minimum version to something higher than what
2424   // we've now set the maximum to, this will result in an inconsistent version
2425   // range unless we fix it up. This will override their preference, but we only
2426   // do this for sites critical to the operation of the browser (e.g. update
2427   // servers) and telemetry experiments.
2428   if (range.min > range.max) {
2429     range.min = range.max;
2430   }
2431 
2432   if (SSL_VersionRangeSet(fd, &range) != SECSuccess) {
2433     return NS_ERROR_FAILURE;
2434   }
2435   infoObject->SetTLSVersionRange(range);
2436 
2437   // when adjustForTLSIntolerance tweaks the maximum version downward,
2438   // we tell the server using this SCSV so they can detect a downgrade attack
2439   if (range.max < maxEnabledVersion) {
2440     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2441             ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd));
2442     // Some servers will choke if we send the fallback SCSV with TLS 1.2.
2443     if (range.max < SSL_LIBRARY_VERSION_TLS_1_2) {
2444       if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_FALLBACK_SCSV, true)) {
2445         return NS_ERROR_FAILURE;
2446       }
2447     }
2448     // tell NSS the max enabled version to make anti-downgrade effective
2449     if (SECSuccess != SSL_SetDowngradeCheckVersion(fd, maxEnabledVersion)) {
2450       return NS_ERROR_FAILURE;
2451     }
2452   }
2453 
2454   if (range.max > SSL_LIBRARY_VERSION_TLS_1_2) {
2455     SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, false);
2456     SSL_CipherPrefSet(fd, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, false);
2457     SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, false);
2458     SSL_CipherPrefSet(fd, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, false);
2459   }
2460 
2461   // Include a modest set of named groups.
2462   // Please change getKeaGroupName in nsNSSCallbacks.cpp when changing the list
2463   // here.
2464   const SSLNamedGroup namedGroups[] = {
2465       ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
2466       ssl_grp_ec_secp521r1,  ssl_grp_ffdhe_2048,   ssl_grp_ffdhe_3072};
2467   if (SECSuccess != SSL_NamedGroupConfig(fd, namedGroups,
2468                                          mozilla::ArrayLength(namedGroups))) {
2469     return NS_ERROR_FAILURE;
2470   }
2471   // This ensures that we send key shares for X25519 and P-256 in TLS 1.3, so
2472   // that servers are less likely to use HelloRetryRequest.
2473   if (SECSuccess != SSL_SendAdditionalKeyShares(fd, 1)) {
2474     return NS_ERROR_FAILURE;
2475   }
2476 
2477   if (SECSuccess != SSL_SignatureSchemePrefSet(
2478                         fd, sEnabledSignatureSchemes,
2479                         mozilla::ArrayLength(sEnabledSignatureSchemes))) {
2480     return NS_ERROR_FAILURE;
2481   }
2482 
2483   bool enabled = infoObject->SharedState().IsOCSPStaplingEnabled();
2484   if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_OCSP_STAPLING, enabled)) {
2485     return NS_ERROR_FAILURE;
2486   }
2487 
2488   bool sctsEnabled = infoObject->SharedState().IsSignedCertTimestampsEnabled();
2489   if (SECSuccess !=
2490       SSL_OptionSet(fd, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, sctsEnabled)) {
2491     return NS_ERROR_FAILURE;
2492   }
2493 
2494   if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
2495     return NS_ERROR_FAILURE;
2496   }
2497 
2498   // Set the Peer ID so that SSL proxy connections work properly and to
2499   // separate anonymous and/or private browsing connections.
2500   uint32_t flags = infoObject->GetProviderFlags();
2501   nsAutoCString peerId;
2502   if (flags & nsISocketProvider::ANONYMOUS_CONNECT) {  // See bug 466080
2503     peerId.AppendLiteral("anon:");
2504   }
2505   if (flags & nsISocketProvider::NO_PERMANENT_STORAGE) {
2506     peerId.AppendLiteral("private:");
2507   }
2508   if (flags & nsISocketProvider::MITM_OK) {
2509     peerId.AppendLiteral("bypassAuth:");
2510   }
2511   if (flags & nsISocketProvider::BE_CONSERVATIVE) {
2512     peerId.AppendLiteral("beConservative:");
2513   }
2514 
2515   peerId.AppendPrintf("tlsflags0x%08x:", infoObject->GetProviderTlsFlags());
2516 
2517   peerId.Append(host);
2518   peerId.Append(':');
2519   peerId.AppendInt(port);
2520   nsAutoCString suffix;
2521   infoObject->GetOriginAttributes().CreateSuffix(suffix);
2522   peerId.Append(suffix);
2523   if (SECSuccess != SSL_SetSockPeerID(fd, peerId.get())) {
2524     return NS_ERROR_FAILURE;
2525   }
2526 
2527   return NS_OK;
2528 }
2529 
nsSSLIOLayerAddToSocket(int32_t family,const char * host,int32_t port,nsIProxyInfo * proxy,const OriginAttributes & originAttributes,PRFileDesc * fd,nsISupports ** info,bool forSTARTTLS,uint32_t providerFlags,uint32_t providerTlsFlags)2530 nsresult nsSSLIOLayerAddToSocket(int32_t family, const char* host, int32_t port,
2531                                  nsIProxyInfo* proxy,
2532                                  const OriginAttributes& originAttributes,
2533                                  PRFileDesc* fd, nsISupports** info,
2534                                  bool forSTARTTLS, uint32_t providerFlags,
2535                                  uint32_t providerTlsFlags) {
2536   PRFileDesc* layer = nullptr;
2537   PRFileDesc* plaintextLayer = nullptr;
2538   nsresult rv;
2539   PRStatus stat;
2540 
2541   SharedSSLState* sharedState = nullptr;
2542   RefPtr<SharedSSLState> allocatedState;
2543   if (providerTlsFlags) {
2544     allocatedState = new SharedSSLState(providerTlsFlags);
2545     sharedState = allocatedState.get();
2546   } else {
2547     sharedState = (providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE)
2548                       ? PrivateSSLState()
2549                       : PublicSSLState();
2550   }
2551 
2552   nsNSSSocketInfo* infoObject =
2553       new nsNSSSocketInfo(*sharedState, providerFlags, providerTlsFlags);
2554   if (!infoObject) return NS_ERROR_FAILURE;
2555 
2556   NS_ADDREF(infoObject);
2557   infoObject->SetForSTARTTLS(forSTARTTLS);
2558   infoObject->SetHostName(host);
2559   infoObject->SetPort(port);
2560   infoObject->SetOriginAttributes(originAttributes);
2561   if (allocatedState) {
2562     infoObject->SetSharedOwningReference(allocatedState);
2563   }
2564 
2565   bool haveProxy = false;
2566   if (proxy) {
2567     nsCString proxyHost;
2568     proxy->GetHost(proxyHost);
2569     haveProxy = !proxyHost.IsEmpty();
2570   }
2571 
2572   // A plaintext observer shim is inserted so we can observe some protocol
2573   // details without modifying nss
2574   plaintextLayer =
2575       PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity,
2576                            &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods);
2577   if (plaintextLayer) {
2578     plaintextLayer->secret = (PRFilePrivate*)infoObject;
2579     stat = PR_PushIOLayer(fd, PR_TOP_IO_LAYER, plaintextLayer);
2580     if (stat == PR_FAILURE) {
2581       plaintextLayer->dtor(plaintextLayer);
2582       plaintextLayer = nullptr;
2583     }
2584   }
2585 
2586   PRFileDesc* sslSock = nsSSLIOLayerImportFD(fd, infoObject, host);
2587   if (!sslSock) {
2588     MOZ_ASSERT_UNREACHABLE("NSS: Error importing socket");
2589     goto loser;
2590   }
2591 
2592   infoObject->SetFileDescPtr(sslSock);
2593 
2594   rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, haveProxy, host, port,
2595                               infoObject);
2596 
2597   if (NS_FAILED(rv)) goto loser;
2598 
2599   // Now, layer ourselves on top of the SSL socket...
2600   layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
2601                                &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
2602   if (!layer) goto loser;
2603 
2604   layer->secret = (PRFilePrivate*)infoObject;
2605   stat = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
2606 
2607   if (stat == PR_FAILURE) {
2608     goto loser;
2609   }
2610 
2611   MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
2612           ("[%p] Socket set up\n", (void*)sslSock));
2613   infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**)(info));
2614 
2615   // We are going use a clear connection first //
2616   if (forSTARTTLS || haveProxy) {
2617     infoObject->SetHandshakeNotPending();
2618   }
2619 
2620   infoObject->SharedState().NoteSocketCreated();
2621 
2622   return NS_OK;
2623 loser:
2624   NS_IF_RELEASE(infoObject);
2625   if (layer) {
2626     layer->dtor(layer);
2627   }
2628   if (plaintextLayer) {
2629     // Note that PR_*IOLayer operations may modify the stack of fds, so a
2630     // previously-valid pointer may no longer point to what we think it points
2631     // to after calling PR_PopIOLayer. We must operate on the pointer returned
2632     // by PR_PopIOLayer.
2633     plaintextLayer =
2634         PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
2635     plaintextLayer->dtor(plaintextLayer);
2636   }
2637   return NS_ERROR_FAILURE;
2638 }
2639