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