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