Coverage Report

Created: 2018-09-25 14:53

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