Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/nsNSSCallbacks.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 "nsNSSCallbacks.h"
8
9
#include "PSMRunnable.h"
10
#include "ScopedNSSTypes.h"
11
#include "SharedCertVerifier.h"
12
#include "SharedSSLState.h"
13
#include "mozilla/ArrayUtils.h"
14
#include "mozilla/Assertions.h"
15
#include "mozilla/Casting.h"
16
#include "mozilla/RefPtr.h"
17
#include "mozilla/Telemetry.h"
18
#include "mozilla/Unused.h"
19
#include "nsContentUtils.h"
20
#include "nsICertOverrideService.h"
21
#include "nsIHttpChannelInternal.h"
22
#include "nsIPrompt.h"
23
#include "nsISupportsPriority.h"
24
#include "nsIStreamLoader.h"
25
#include "nsITokenDialogs.h"
26
#include "nsIUploadChannel.h"
27
#include "nsIWebProgressListener.h"
28
#include "nsNSSCertHelper.h"
29
#include "nsNSSCertificate.h"
30
#include "nsNSSComponent.h"
31
#include "nsNSSIOLayer.h"
32
#include "nsNetUtil.h"
33
#include "nsProtectedAuthThread.h"
34
#include "nsProxyRelease.h"
35
#include "nsStringStream.h"
36
#include "pkix/pkixtypes.h"
37
#include "ssl.h"
38
#include "sslproto.h"
39
40
#include "TrustOverrideUtils.h"
41
#include "TrustOverride-SymantecData.inc"
42
#include "TrustOverride-AppleGoogleDigiCertData.inc"
43
#include "TrustOverride-TestImminentDistrustData.inc"
44
45
using namespace mozilla;
46
using namespace mozilla::pkix;
47
using namespace mozilla::psm;
48
49
extern LazyLogModule gPIPNSSLog;
50
51
static void AccumulateCipherSuite(Telemetry::HistogramID probe,
52
                                  const SSLChannelInfo& channelInfo);
53
54
namespace {
55
56
// Bits in bit mask for SSL_REASONS_FOR_NOT_FALSE_STARTING telemetry probe
57
// These bits are numbered so that the least subtle issues have higher values.
58
// This should make it easier for us to interpret the results.
59
const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4;
60
const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2;
61
const uint32_t KEA_NOT_SUPPORTED = 1;
62
63
} // namespace
64
65
class OCSPRequest final : public nsIStreamLoaderObserver
66
                        , public nsIRunnable
67
{
68
public:
69
  OCSPRequest(const nsCString& aiaLocation,
70
              const OriginAttributes& originAttributes,
71
              Vector<uint8_t>&& ocspRequest,
72
              TimeDuration timeout);
73
74
  NS_DECL_THREADSAFE_ISUPPORTS
75
  NS_DECL_NSISTREAMLOADEROBSERVER
76
  NS_DECL_NSIRUNNABLE
77
78
  nsresult DispatchToMainThreadAndWait();
79
  nsresult GetResponse(/*out*/ Vector<uint8_t>& response);
80
81
private:
82
0
  ~OCSPRequest() = default;
83
84
  static void OnTimeout(nsITimer* timer, void* closure);
85
  nsresult NotifyDone(nsresult rv, MonitorAutoLock& proofOfLock);
86
87
  // mMonitor provides the memory barrier protecting these member variables.
88
  // What happens is the originating thread creates an OCSPRequest object with
89
  // the information necessary to perform an OCSP request. It sends the object
90
  // to the main thread and waits on the monitor for the operation to complete.
91
  // On the main thread, a channel is set up to perform the request. This gets
92
  // dispatched to necko. At the same time, a timeout timer is initialized. If
93
  // the necko request completes, the response data is filled out, mNotifiedDone
94
  // is set to true, and the monitor is notified. The original thread then wakes
95
  // up and continues with the results that have been filled out. If the request
96
  // times out, again the response data is filled out, mNotifiedDone is set to
97
  // true, and the monitor is notified. The first of these two events wins. That
98
  // is, if the timeout timer fires but the request completes shortly after, the
99
  // caller will see the request as having timed out.
100
  // When the request completes (i.e. OnStreamComplete runs), the timer will be
101
  // cancelled. This is how we know the closure in OnTimeout is valid. If the
102
  // timer fires before OnStreamComplete runs, it should be safe to not cancel
103
  // the request because necko has a strong reference to it.
104
  Monitor mMonitor;
105
  bool mNotifiedDone;
106
  nsCOMPtr<nsIStreamLoader> mLoader;
107
  const nsCString mAIALocation;
108
  const OriginAttributes mOriginAttributes;
109
  const Vector<uint8_t> mPOSTData;
110
  const TimeDuration mTimeout;
111
  nsCOMPtr<nsITimer> mTimeoutTimer;
112
  TimeStamp mStartTime;
113
  nsresult mResponseResult;
114
  Vector<uint8_t> mResponseBytes;
115
};
116
117
NS_IMPL_ISUPPORTS(OCSPRequest, nsIStreamLoaderObserver, nsIRunnable)
118
119
OCSPRequest::OCSPRequest(const nsCString& aiaLocation,
120
                         const OriginAttributes& originAttributes,
121
                         Vector<uint8_t>&& ocspRequest,
122
                         TimeDuration timeout)
123
  : mMonitor("OCSPRequest.mMonitor")
124
  , mNotifiedDone(false)
125
  , mLoader(nullptr)
126
  , mAIALocation(aiaLocation)
127
  , mOriginAttributes(originAttributes)
128
  , mPOSTData(std::move(ocspRequest))
129
  , mTimeout(timeout)
130
  , mTimeoutTimer(nullptr)
131
  , mStartTime()
132
  , mResponseResult(NS_ERROR_FAILURE)
133
  , mResponseBytes()
134
0
{
135
0
}
136
137
nsresult
138
OCSPRequest::DispatchToMainThreadAndWait()
139
0
{
140
0
  MOZ_ASSERT(!NS_IsMainThread());
141
0
  if (NS_IsMainThread()) {
142
0
    return NS_ERROR_FAILURE;
143
0
  }
144
0
145
0
  MonitorAutoLock lock(mMonitor);
146
0
  nsresult rv = NS_DispatchToMainThread(this);
147
0
  if (NS_FAILED(rv)) {
148
0
    return rv;
149
0
  }
150
0
  while (!mNotifiedDone) {
151
0
    lock.Wait();
152
0
  }
153
0
154
0
  TimeStamp endTime = TimeStamp::Now();
155
0
  // CERT_VALIDATION_HTTP_REQUEST_RESULT:
156
0
  // 0: request timed out
157
0
  // 1: request succeeded
158
0
  // 2: request failed
159
0
  // 3: internal error
160
0
  // If mStartTime was never set, we consider this an internal error.
161
0
  // Otherwise, we managed to at least send the request.
162
0
  if (mStartTime.IsNull()) {
163
0
    Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 3);
164
0
  } else if (mResponseResult == NS_ERROR_NET_TIMEOUT) {
165
0
    Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 0);
166
0
    Telemetry::AccumulateTimeDelta(
167
0
      Telemetry::CERT_VALIDATION_HTTP_REQUEST_CANCELED_TIME,
168
0
      mStartTime, endTime);
169
0
  } else if (NS_SUCCEEDED(mResponseResult)) {
170
0
    Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 1);
171
0
    Telemetry::AccumulateTimeDelta(
172
0
      Telemetry::CERT_VALIDATION_HTTP_REQUEST_SUCCEEDED_TIME,
173
0
      mStartTime, endTime);
174
0
  } else {
175
0
    Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 2);
176
0
    Telemetry::AccumulateTimeDelta(
177
0
      Telemetry::CERT_VALIDATION_HTTP_REQUEST_FAILED_TIME,
178
0
      mStartTime, endTime);
179
0
  }
180
0
  return rv;
181
0
}
182
183
nsresult
184
OCSPRequest::GetResponse(/*out*/ Vector<uint8_t>& response)
185
0
{
186
0
  MOZ_ASSERT(!NS_IsMainThread());
187
0
  if (NS_IsMainThread()) {
188
0
    return NS_ERROR_FAILURE;
189
0
  }
190
0
191
0
  MonitorAutoLock lock(mMonitor);
192
0
  if (!mNotifiedDone) {
193
0
    return NS_ERROR_IN_PROGRESS;
194
0
  }
195
0
  if (NS_FAILED(mResponseResult)) {
196
0
    return mResponseResult;
197
0
  }
198
0
  response.clear();
199
0
  if (!response.append(mResponseBytes.begin(), mResponseBytes.length())) {
200
0
    return NS_ERROR_OUT_OF_MEMORY;
201
0
  }
202
0
  return NS_OK;
203
0
}
204
205
static NS_NAMED_LITERAL_CSTRING(OCSP_REQUEST_MIME_TYPE,
206
                                "application/ocsp-request");
207
static NS_NAMED_LITERAL_CSTRING(OCSP_REQUEST_METHOD, "POST");
208
209
NS_IMETHODIMP
210
OCSPRequest::Run()
211
0
{
212
0
  MOZ_ASSERT(NS_IsMainThread());
213
0
  if (!NS_IsMainThread()) {
214
0
    return NS_ERROR_FAILURE;
215
0
  }
216
0
217
0
  MonitorAutoLock lock(mMonitor);
218
0
219
0
  nsCOMPtr<nsIIOService> ios = do_GetIOService();
220
0
  if (!ios) {
221
0
    return NotifyDone(NS_ERROR_FAILURE, lock);
222
0
  }
223
0
224
0
  nsCOMPtr<nsIURI> uri;
225
0
  nsresult rv = NS_NewURI(getter_AddRefs(uri), mAIALocation, nullptr, nullptr,
226
0
                          ios);
227
0
  if (NS_FAILED(rv)) {
228
0
    return NotifyDone(NS_ERROR_MALFORMED_URI, lock);
229
0
  }
230
0
  nsAutoCString scheme;
231
0
  rv = uri->GetScheme(scheme);
232
0
  if (NS_FAILED(rv)) {
233
0
    return NotifyDone(rv, lock);
234
0
  }
235
0
  if (!scheme.LowerCaseEqualsLiteral("http")) {
236
0
    return NotifyDone(NS_ERROR_MALFORMED_URI, lock);
237
0
  }
238
0
239
0
  nsCOMPtr<nsIChannel> channel;
240
0
  rv = ios->NewChannel2(mAIALocation,
241
0
                        nullptr,
242
0
                        nullptr,
243
0
                        nullptr, // aLoadingNode
244
0
                        nsContentUtils::GetSystemPrincipal(),
245
0
                        nullptr, // aTriggeringPrincipal
246
0
                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
247
0
                        nsIContentPolicy::TYPE_OTHER,
248
0
                        getter_AddRefs(channel));
249
0
  if (NS_FAILED(rv)) {
250
0
    return NotifyDone(rv, lock);
251
0
  }
252
0
253
0
  // Security operations scheduled through normal HTTP channels are given
254
0
  // high priority to accommodate real time OCSP transactions.
255
0
  nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(channel);
256
0
  if (priorityChannel) {
257
0
    priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
258
0
  }
259
0
260
0
  channel->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS |
261
0
                        nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
262
0
263
0
  // For OCSP requests, only the first party domain and private browsing id
264
0
  // aspects of origin attributes are used. This means that:
265
0
  // a) if first party isolation is enabled, OCSP requests will be isolated
266
0
  // according to the first party domain of the original https request
267
0
  // b) OCSP requests are shared across different containers as long as first
268
0
  // party isolation is not enabled and none of the containers are in private
269
0
  // browsing mode.
270
0
  if (mOriginAttributes != OriginAttributes()) {
271
0
    OriginAttributes attrs;
272
0
    attrs.mFirstPartyDomain = mOriginAttributes.mFirstPartyDomain;
273
0
    attrs.mPrivateBrowsingId = mOriginAttributes.mPrivateBrowsingId;
274
0
275
0
    nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
276
0
    if (!loadInfo) {
277
0
      return NotifyDone(NS_ERROR_FAILURE, lock);
278
0
    }
279
0
    rv = loadInfo->SetOriginAttributes(attrs);
280
0
    if (NS_FAILED(rv)) {
281
0
      return NotifyDone(rv, lock);
282
0
    }
283
0
  }
284
0
285
0
  nsCOMPtr<nsIInputStream> uploadStream;
286
0
  rv = NS_NewByteInputStream(getter_AddRefs(uploadStream),
287
0
                             reinterpret_cast<const char*>(mPOSTData.begin()),
288
0
                             mPOSTData.length());
289
0
  if (NS_FAILED(rv)) {
290
0
    return NotifyDone(rv, lock);
291
0
  }
292
0
  nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(channel));
293
0
  if (!uploadChannel) {
294
0
    return NotifyDone(NS_ERROR_FAILURE, lock);
295
0
  }
296
0
  rv = uploadChannel->SetUploadStream(uploadStream, OCSP_REQUEST_MIME_TYPE, -1);
297
0
  if (NS_FAILED(rv)) {
298
0
    return NotifyDone(rv, lock);
299
0
  }
300
0
  // Do not use SPDY for internal security operations. It could result
301
0
  // in the silent upgrade to ssl, which in turn could require an SSL
302
0
  // operation to fulfill something like an OCSP fetch, which is an
303
0
  // endless loop.
304
0
  nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(channel);
305
0
  if (!internalChannel) {
306
0
    return NotifyDone(rv, lock);
307
0
  }
308
0
  rv = internalChannel->SetAllowSpdy(false);
309
0
  if (NS_FAILED(rv)) {
310
0
    return NotifyDone(rv, lock);
311
0
  }
312
0
  nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(channel);
313
0
  if (!hchan) {
314
0
    return NotifyDone(NS_ERROR_FAILURE, lock);
315
0
  }
316
0
  rv = hchan->SetAllowSTS(false);
317
0
  if (NS_FAILED(rv)) {
318
0
    return NotifyDone(rv, lock);
319
0
  }
320
0
  rv = hchan->SetRequestMethod(OCSP_REQUEST_METHOD);
321
0
  if (NS_FAILED(rv)) {
322
0
    return NotifyDone(rv, lock);
323
0
  }
324
0
325
0
  rv = NS_NewStreamLoader(getter_AddRefs(mLoader), this);
326
0
  if (NS_FAILED(rv)) {
327
0
    return NotifyDone(rv, lock);
328
0
  }
329
0
330
0
  rv = NS_NewTimerWithFuncCallback(getter_AddRefs(mTimeoutTimer),
331
0
                                   OCSPRequest::OnTimeout,
332
0
                                   this,
333
0
                                   mTimeout.ToMilliseconds(),
334
0
                                   nsITimer::TYPE_ONE_SHOT,
335
0
                                   "OCSPRequest::Run");
336
0
  if (NS_FAILED(rv)) {
337
0
    return NotifyDone(rv, lock);
338
0
  }
339
0
  rv = hchan->AsyncOpen2(this->mLoader);
340
0
  if (NS_FAILED(rv)) {
341
0
    return NotifyDone(rv, lock);
342
0
  }
343
0
  mStartTime = TimeStamp::Now();
344
0
  return NS_OK;
345
0
}
346
347
nsresult
348
OCSPRequest::NotifyDone(nsresult rv, MonitorAutoLock& lock)
349
0
{
350
0
  MOZ_ASSERT(NS_IsMainThread());
351
0
  if (!NS_IsMainThread()) {
352
0
    return NS_ERROR_FAILURE;
353
0
  }
354
0
355
0
  if (mNotifiedDone) {
356
0
    return mResponseResult;
357
0
  }
358
0
  mLoader = nullptr;
359
0
  mResponseResult = rv;
360
0
  if (mTimeoutTimer) {
361
0
    Unused << mTimeoutTimer->Cancel();
362
0
  }
363
0
  mNotifiedDone = true;
364
0
  lock.Notify();
365
0
  return rv;
366
0
}
367
368
NS_IMETHODIMP
369
OCSPRequest::OnStreamComplete(nsIStreamLoader* aLoader,
370
                              nsISupports* aContext,
371
                              nsresult aStatus,
372
                              uint32_t responseLen,
373
                              const uint8_t* responseBytes)
374
0
{
375
0
  MOZ_ASSERT(NS_IsMainThread());
376
0
  if (!NS_IsMainThread()) {
377
0
    return NS_ERROR_FAILURE;
378
0
  }
379
0
380
0
  MonitorAutoLock lock(mMonitor);
381
0
382
0
  nsCOMPtr<nsIRequest> req;
383
0
  nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
384
0
  if (NS_FAILED(rv)) {
385
0
    return NotifyDone(rv, lock);
386
0
  }
387
0
388
0
  if (NS_FAILED(aStatus)) {
389
0
    return NotifyDone(aStatus, lock);
390
0
  }
391
0
392
0
  nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(req);
393
0
  if (!hchan) {
394
0
    return NotifyDone(NS_ERROR_FAILURE, lock);
395
0
  }
396
0
397
0
  bool requestSucceeded;
398
0
  rv = hchan->GetRequestSucceeded(&requestSucceeded);
399
0
  if (NS_FAILED(rv)) {
400
0
    return NotifyDone(rv, lock);
401
0
  }
402
0
  if (!requestSucceeded) {
403
0
    return NotifyDone(NS_ERROR_FAILURE, lock);
404
0
  }
405
0
406
0
  unsigned int rcode;
407
0
  rv = hchan->GetResponseStatus(&rcode);
408
0
  if (NS_FAILED(rv)) {
409
0
    return NotifyDone(rv, lock);
410
0
  }
411
0
  if (rcode != 200) {
412
0
    return NotifyDone(NS_ERROR_FAILURE, lock);
413
0
  }
414
0
415
0
  mResponseBytes.clear();
416
0
  if (!mResponseBytes.append(responseBytes, responseLen)) {
417
0
    return NotifyDone(NS_ERROR_OUT_OF_MEMORY, lock);
418
0
  }
419
0
  mResponseResult = aStatus;
420
0
421
0
  return NotifyDone(NS_OK, lock);
422
0
}
423
424
void
425
OCSPRequest::OnTimeout(nsITimer* timer, void* closure)
426
0
{
427
0
  MOZ_ASSERT(NS_IsMainThread());
428
0
  if (!NS_IsMainThread()) {
429
0
    return;
430
0
  }
431
0
432
0
  // We know the OCSPRequest is still alive because if the request had completed
433
0
  // (i.e. OnStreamComplete ran), the timer would have been cancelled in
434
0
  // NotifyDone.
435
0
  OCSPRequest* self = static_cast<OCSPRequest*>(closure);
436
0
  MonitorAutoLock lock(self->mMonitor);
437
0
  self->mTimeoutTimer = nullptr;
438
0
  self->NotifyDone(NS_ERROR_NET_TIMEOUT, lock);
439
0
}
440
441
mozilla::pkix::Result
442
DoOCSPRequest(const nsCString& aiaLocation,
443
              const OriginAttributes& originAttributes,
444
              Vector<uint8_t>&& ocspRequest,
445
              TimeDuration timeout,
446
              /*out*/ Vector<uint8_t>& result)
447
0
{
448
0
  MOZ_ASSERT(!NS_IsMainThread());
449
0
  if (NS_IsMainThread()) {
450
0
    return mozilla::pkix::Result::ERROR_OCSP_UNKNOWN_CERT;
451
0
  }
452
0
453
0
  result.clear();
454
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
455
0
          ("DoOCSPRequest to '%s'", aiaLocation.get()));
456
0
457
0
  nsCOMPtr<nsIEventTarget> sts = do_GetService(
458
0
    NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
459
0
  MOZ_ASSERT(sts);
460
0
  if (!sts) {
461
0
    return mozilla::pkix::Result::FATAL_ERROR_INVALID_STATE;
462
0
  }
463
0
  bool onSTSThread;
464
0
  nsresult rv = sts->IsOnCurrentThread(&onSTSThread);
465
0
  if (NS_FAILED(rv)) {
466
0
    return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
467
0
  }
468
0
  MOZ_ASSERT(!onSTSThread);
469
0
  if (onSTSThread) {
470
0
    return mozilla::pkix::Result::FATAL_ERROR_INVALID_STATE;
471
0
  }
472
0
473
0
  RefPtr<OCSPRequest> request(new OCSPRequest(aiaLocation, originAttributes,
474
0
                                              std::move(ocspRequest), timeout));
475
0
  rv = request->DispatchToMainThreadAndWait();
476
0
  if (NS_FAILED(rv)) {
477
0
    return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
478
0
  }
479
0
  rv = request->GetResponse(result);
480
0
  if (NS_FAILED(rv)) {
481
0
    if (rv == NS_ERROR_MALFORMED_URI) {
482
0
      return mozilla::pkix::Result::ERROR_CERT_BAD_ACCESS_LOCATION;
483
0
    }
484
0
    return mozilla::pkix::Result::ERROR_OCSP_SERVER_ERROR;
485
0
  }
486
0
  return Success;
487
0
}
488
489
static char*
490
ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIInterfaceRequestor *ir)
491
0
{
492
0
  if (!NS_IsMainThread()) {
493
0
    NS_ERROR("ShowProtectedAuthPrompt called off the main thread");
494
0
    return nullptr;
495
0
  }
496
0
497
0
  char* protAuthRetVal = nullptr;
498
0
499
0
  // Get protected auth dialogs
500
0
  nsCOMPtr<nsITokenDialogs> dialogs;
501
0
  nsresult nsrv = getNSSDialogs(getter_AddRefs(dialogs),
502
0
                                NS_GET_IID(nsITokenDialogs),
503
0
                                NS_TOKENDIALOGS_CONTRACTID);
504
0
  if (NS_SUCCEEDED(nsrv))
505
0
  {
506
0
    nsProtectedAuthThread* protectedAuthRunnable = new nsProtectedAuthThread();
507
0
    if (protectedAuthRunnable)
508
0
    {
509
0
      NS_ADDREF(protectedAuthRunnable);
510
0
511
0
      protectedAuthRunnable->SetParams(slot);
512
0
513
0
      nsCOMPtr<nsIProtectedAuthThread> runnable = do_QueryInterface(protectedAuthRunnable);
514
0
      if (runnable)
515
0
      {
516
0
        nsrv = dialogs->DisplayProtectedAuth(ir, runnable);
517
0
518
0
        // We call join on the thread,
519
0
        // so we can be sure that no simultaneous access will happen.
520
0
        protectedAuthRunnable->Join();
521
0
522
0
        if (NS_SUCCEEDED(nsrv))
523
0
        {
524
0
          SECStatus rv = protectedAuthRunnable->GetResult();
525
0
          switch (rv)
526
0
          {
527
0
              case SECSuccess:
528
0
                  protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
529
0
                  break;
530
0
              case SECWouldBlock:
531
0
                  protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_RETRY));
532
0
                  break;
533
0
              default:
534
0
                  protAuthRetVal = nullptr;
535
0
                  break;
536
0
          }
537
0
        }
538
0
      }
539
0
540
0
      NS_RELEASE(protectedAuthRunnable);
541
0
    }
542
0
  }
543
0
544
0
  return protAuthRetVal;
545
0
}
546
547
class PK11PasswordPromptRunnable : public SyncRunnableBase
548
{
549
public:
550
  PK11PasswordPromptRunnable(PK11SlotInfo* slot,
551
                             nsIInterfaceRequestor* ir)
552
    : mResult(nullptr),
553
      mSlot(slot),
554
      mIR(ir)
555
0
  {
556
0
  }
557
  virtual ~PK11PasswordPromptRunnable() = default;
558
559
  char * mResult; // out
560
  virtual void RunOnTargetThread() override;
561
private:
562
  PK11SlotInfo* const mSlot; // in
563
  nsIInterfaceRequestor* const mIR; // in
564
};
565
566
void
567
PK11PasswordPromptRunnable::RunOnTargetThread()
568
0
{
569
0
  nsresult rv;
570
0
  nsCOMPtr<nsIPrompt> prompt;
571
0
  if (!mIR) {
572
0
    rv = nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
573
0
    if (NS_FAILED(rv)) {
574
0
      return;
575
0
    }
576
0
  } else {
577
0
    prompt = do_GetInterface(mIR);
578
0
    MOZ_ASSERT(prompt, "Interface requestor should implement nsIPrompt");
579
0
  }
580
0
581
0
  if (!prompt) {
582
0
    return;
583
0
  }
584
0
585
0
  if (PK11_ProtectedAuthenticationPath(mSlot)) {
586
0
    mResult = ShowProtectedAuthPrompt(mSlot, mIR);
587
0
    return;
588
0
  }
589
0
590
0
  nsAutoString promptString;
591
0
  if (PK11_IsInternal(mSlot)) {
592
0
    rv = GetPIPNSSBundleString("CertPassPromptDefault", promptString);
593
0
  } else {
594
0
    NS_ConvertUTF8toUTF16 tokenName(PK11_GetTokenName(mSlot));
595
0
    const char16_t* formatStrings[] = {
596
0
      tokenName.get(),
597
0
    };
598
0
    rv = PIPBundleFormatStringFromName("CertPassPrompt", formatStrings,
599
0
                                       ArrayLength(formatStrings),
600
0
                                       promptString);
601
0
  }
602
0
  if (NS_FAILED(rv)) {
603
0
    return;
604
0
  }
605
0
606
0
  nsString password;
607
0
  // |checkState| is unused because |checkMsg| (the argument just before it) is
608
0
  // null, but XPConnect requires it to point to a valid bool nonetheless.
609
0
  bool checkState = false;
610
0
  bool userClickedOK = false;
611
0
  rv = prompt->PromptPassword(nullptr, promptString.get(),
612
0
                              getter_Copies(password), nullptr, &checkState,
613
0
                              &userClickedOK);
614
0
  if (NS_FAILED(rv) || !userClickedOK) {
615
0
    return;
616
0
  }
617
0
618
0
  mResult = ToNewUTF8String(password);
619
0
}
620
621
char*
622
PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg)
623
0
{
624
0
  RefPtr<PK11PasswordPromptRunnable> runnable(
625
0
    new PK11PasswordPromptRunnable(slot,
626
0
                                   static_cast<nsIInterfaceRequestor*>(arg)));
627
0
  runnable->DispatchToMainThreadAndWait();
628
0
  return runnable->mResult;
629
0
}
630
631
static nsCString
632
getKeaGroupName(uint32_t aKeaGroup)
633
0
{
634
0
  nsCString groupName;
635
0
  switch (aKeaGroup) {
636
0
    case ssl_grp_ec_secp256r1:
637
0
      groupName = NS_LITERAL_CSTRING("P256");
638
0
      break;
639
0
    case ssl_grp_ec_secp384r1:
640
0
      groupName = NS_LITERAL_CSTRING("P384");
641
0
      break;
642
0
    case ssl_grp_ec_secp521r1:
643
0
      groupName = NS_LITERAL_CSTRING("P521");
644
0
      break;
645
0
    case ssl_grp_ec_curve25519:
646
0
      groupName = NS_LITERAL_CSTRING("x25519");
647
0
      break;
648
0
    case ssl_grp_ffdhe_2048:
649
0
      groupName = NS_LITERAL_CSTRING("FF 2048");
650
0
      break;
651
0
    case ssl_grp_ffdhe_3072:
652
0
      groupName = NS_LITERAL_CSTRING("FF 3072");
653
0
      break;
654
0
    case ssl_grp_none:
655
0
      groupName = NS_LITERAL_CSTRING("none");
656
0
      break;
657
0
    case ssl_grp_ffdhe_custom:
658
0
      groupName = NS_LITERAL_CSTRING("custom");
659
0
      break;
660
0
    // All other groups are not enabled in Firefox. See namedGroups in
661
0
    // nsNSSIOLayer.cpp.
662
0
    default:
663
0
      // This really shouldn't happen!
664
0
      MOZ_ASSERT_UNREACHABLE("Invalid key exchange group.");
665
0
      groupName = NS_LITERAL_CSTRING("unknown group");
666
0
  }
667
0
  return groupName;
668
0
}
669
670
static nsCString
671
getSignatureName(uint32_t aSignatureScheme)
672
0
{
673
0
  nsCString signatureName;
674
0
  switch (aSignatureScheme) {
675
0
    case ssl_sig_none:
676
0
      signatureName = NS_LITERAL_CSTRING("none");
677
0
      break;
678
0
    case ssl_sig_rsa_pkcs1_sha1:
679
0
      signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA1");
680
0
      break;
681
0
    case ssl_sig_rsa_pkcs1_sha256:
682
0
      signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA256");
683
0
      break;
684
0
    case ssl_sig_rsa_pkcs1_sha384:
685
0
      signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA384");
686
0
      break;
687
0
    case  ssl_sig_rsa_pkcs1_sha512:
688
0
      signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA512");
689
0
      break;
690
0
    case ssl_sig_ecdsa_secp256r1_sha256:
691
0
      signatureName = NS_LITERAL_CSTRING("ECDSA-P256-SHA256");
692
0
      break;
693
0
    case ssl_sig_ecdsa_secp384r1_sha384:
694
0
      signatureName = NS_LITERAL_CSTRING("ECDSA-P384-SHA384");
695
0
      break;
696
0
    case ssl_sig_ecdsa_secp521r1_sha512:
697
0
      signatureName = NS_LITERAL_CSTRING("ECDSA-P521-SHA512");
698
0
      break;
699
0
    case ssl_sig_rsa_pss_sha256:
700
0
      signatureName = NS_LITERAL_CSTRING("RSA-PSS-SHA256");
701
0
      break;
702
0
    case ssl_sig_rsa_pss_sha384:
703
0
      signatureName = NS_LITERAL_CSTRING("RSA-PSS-SHA384");
704
0
      break;
705
0
    case ssl_sig_rsa_pss_sha512:
706
0
      signatureName = NS_LITERAL_CSTRING("RSA-PSS-SHA512");
707
0
      break;
708
0
    case ssl_sig_ecdsa_sha1:
709
0
      signatureName = NS_LITERAL_CSTRING("ECDSA-SHA1");
710
0
      break;
711
0
    case ssl_sig_rsa_pkcs1_sha1md5:
712
0
      signatureName = NS_LITERAL_CSTRING("RSA-PKCS1-SHA1MD5");
713
0
      break;
714
0
    // All other groups are not enabled in Firefox. See sEnabledSignatureSchemes
715
0
    // in nsNSSIOLayer.cpp.
716
0
    default:
717
0
      // This really shouldn't happen!
718
0
      MOZ_ASSERT_UNREACHABLE("Invalid signature scheme.");
719
0
      signatureName = NS_LITERAL_CSTRING("unknown signature");
720
0
  }
721
0
  return signatureName;
722
0
}
723
724
// call with shutdown prevention lock held
725
static void
726
PreliminaryHandshakeDone(PRFileDesc* fd)
727
0
{
728
0
  nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
729
0
  if (!infoObject)
730
0
    return;
731
0
732
0
  SSLChannelInfo channelInfo;
733
0
  if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) == SECSuccess) {
734
0
    infoObject->SetSSLVersionUsed(channelInfo.protocolVersion);
735
0
    infoObject->SetEarlyDataAccepted(channelInfo.earlyDataAccepted);
736
0
737
0
    SSLCipherSuiteInfo cipherInfo;
738
0
    if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
739
0
                               sizeof cipherInfo) == SECSuccess) {
740
0
      /* Set the Status information */
741
0
      infoObject->mHaveCipherSuiteAndProtocol = true;
742
0
      infoObject->mCipherSuite = channelInfo.cipherSuite;
743
0
      infoObject->mProtocolVersion = channelInfo.protocolVersion & 0xFF;
744
0
      infoObject->mKeaGroup.Assign(getKeaGroupName(channelInfo.keaGroup));
745
0
      infoObject->mSignatureSchemeName.Assign(
746
0
        getSignatureName(channelInfo.signatureScheme));
747
0
      infoObject->SetKEAUsed(channelInfo.keaType);
748
0
      infoObject->SetKEAKeyBits(channelInfo.keaKeyBits);
749
0
      infoObject->SetMACAlgorithmUsed(cipherInfo.macAlgorithm);
750
0
    }
751
0
  }
752
0
753
0
  // Don't update NPN details on renegotiation.
754
0
  if (infoObject->IsPreliminaryHandshakeDone()) {
755
0
    return;
756
0
  }
757
0
758
0
  // Get the NPN value.
759
0
  SSLNextProtoState state;
760
0
  unsigned char npnbuf[256];
761
0
  unsigned int npnlen;
762
0
763
0
  if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen,
764
0
                       AssertedCast<unsigned int>(ArrayLength(npnbuf)))
765
0
        == SECSuccess) {
766
0
    if (state == SSL_NEXT_PROTO_NEGOTIATED ||
767
0
        state == SSL_NEXT_PROTO_SELECTED) {
768
0
      infoObject->SetNegotiatedNPN(BitwiseCast<char*, unsigned char*>(npnbuf),
769
0
                                   npnlen);
770
0
    } else {
771
0
      infoObject->SetNegotiatedNPN(nullptr, 0);
772
0
    }
773
0
    mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE, state);
774
0
  } else {
775
0
    infoObject->SetNegotiatedNPN(nullptr, 0);
776
0
  }
777
0
778
0
  infoObject->SetPreliminaryHandshakeDone();
779
0
}
780
781
SECStatus
782
CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
783
0
{
784
0
  *canFalseStart = false;
785
0
786
0
  nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
787
0
  if (!infoObject) {
788
0
    PR_SetError(PR_INVALID_STATE_ERROR, 0);
789
0
    return SECFailure;
790
0
  }
791
0
792
0
  infoObject->SetFalseStartCallbackCalled();
793
0
794
0
  PreliminaryHandshakeDone(fd);
795
0
796
0
  uint32_t reasonsForNotFalseStarting = 0;
797
0
798
0
  SSLChannelInfo channelInfo;
799
0
  if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
800
0
    return SECSuccess;
801
0
  }
802
0
803
0
  SSLCipherSuiteInfo cipherInfo;
804
0
  if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
805
0
                             sizeof (cipherInfo)) != SECSuccess) {
806
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
807
0
                                      " KEA %d\n", fd,
808
0
                                      static_cast<int32_t>(channelInfo.keaType)));
809
0
    return SECSuccess;
810
0
  }
811
0
812
0
  // Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
813
0
  // TLS 1.3 and later. See Bug 861310 for all the details as to why.
814
0
  if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) {
815
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
816
0
                                      "SSL Version must be TLS 1.2, was %x\n", fd,
817
0
                                      static_cast<int32_t>(channelInfo.protocolVersion)));
818
0
    reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE;
819
0
  }
820
0
821
0
  // See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not.
822
0
  if (channelInfo.keaType != ssl_kea_ecdh) {
823
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] failed - "
824
0
                                      "unsupported KEA %d\n", fd,
825
0
                                      static_cast<int32_t>(channelInfo.keaType)));
826
0
    reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
827
0
  }
828
0
829
0
  // Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
830
0
  // mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
831
0
  // design. See bug 1109766 for more details.
832
0
  if (cipherInfo.macAlgorithm != ssl_mac_aead) {
833
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
834
0
           ("CanFalseStartCallback [%p] failed - non-AEAD cipher used, %d, "
835
0
            "is not supported with False Start.\n", fd,
836
0
            static_cast<int32_t>(cipherInfo.symCipher)));
837
0
    reasonsForNotFalseStarting |= POSSIBLE_CIPHER_SUITE_DOWNGRADE;
838
0
  }
839
0
840
0
  // XXX: An attacker can choose which protocols are advertised in the
841
0
  // NPN extension. TODO(Bug 861311): We should restrict the ability
842
0
  // of an attacker leverage this capability by restricting false start
843
0
  // to the same protocol we previously saw for the server, after the
844
0
  // first successful connection to the server.
845
0
846
0
  Telemetry::Accumulate(Telemetry::SSL_REASONS_FOR_NOT_FALSE_STARTING,
847
0
                        reasonsForNotFalseStarting);
848
0
849
0
  if (reasonsForNotFalseStarting == 0) {
850
0
    *canFalseStart = PR_TRUE;
851
0
    infoObject->SetFalseStarted();
852
0
    infoObject->NoteTimeUntilReady();
853
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("CanFalseStartCallback [%p] ok\n", fd));
854
0
  }
855
0
856
0
  return SECSuccess;
857
0
}
858
859
static void
860
AccumulateNonECCKeySize(Telemetry::HistogramID probe, uint32_t bits)
861
0
{
862
0
  unsigned int value = bits <   512 ?  1 : bits ==   512 ?  2
863
0
                     : bits <   768 ?  3 : bits ==   768 ?  4
864
0
                     : bits <  1024 ?  5 : bits ==  1024 ?  6
865
0
                     : bits <  1280 ?  7 : bits ==  1280 ?  8
866
0
                     : bits <  1536 ?  9 : bits ==  1536 ? 10
867
0
                     : bits <  2048 ? 11 : bits ==  2048 ? 12
868
0
                     : bits <  3072 ? 13 : bits ==  3072 ? 14
869
0
                     : bits <  4096 ? 15 : bits ==  4096 ? 16
870
0
                     : bits <  8192 ? 17 : bits ==  8192 ? 18
871
0
                     : bits < 16384 ? 19 : bits == 16384 ? 20
872
0
                     : 0;
873
0
  Telemetry::Accumulate(probe, value);
874
0
}
875
876
// XXX: This attempts to map a bit count to an ECC named curve identifier. In
877
// the vast majority of situations, we only have the Suite B curves available.
878
// In that case, this mapping works fine. If we were to have more curves
879
// available, the mapping would be ambiguous since there could be multiple
880
// named curves for a given size (e.g. secp256k1 vs. secp256r1). We punt on
881
// that for now. See also NSS bug 323674.
882
static void
883
AccumulateECCCurve(Telemetry::HistogramID probe, uint32_t bits)
884
0
{
885
0
  unsigned int value = bits == 256 ? 23 // P-256
886
0
                     : bits == 384 ? 24 // P-384
887
0
                     : bits == 521 ? 25 // P-521
888
0
                     : 0; // Unknown
889
0
  Telemetry::Accumulate(probe, value);
890
0
}
891
892
static void
893
AccumulateCipherSuite(Telemetry::HistogramID probe, const SSLChannelInfo& channelInfo)
894
0
{
895
0
  uint32_t value;
896
0
  switch (channelInfo.cipherSuite) {
897
0
    // ECDHE key exchange
898
0
    case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: value = 1; break;
899
0
    case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: value = 2; break;
900
0
    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: value = 3; break;
901
0
    case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: value = 4; break;
902
0
    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: value = 5; break;
903
0
    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: value = 6; break;
904
0
    case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 7; break;
905
0
    case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 10; break;
906
0
    case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: value = 11; break;
907
0
    case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: value = 12; break;
908
0
    case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: value = 13; break;
909
0
    case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: value = 14; break;
910
0
    // DHE key exchange
911
0
    case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: value = 21; break;
912
0
    case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 22; break;
913
0
    case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: value = 23; break;
914
0
    case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 24; break;
915
0
    case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 25; break;
916
0
    case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: value = 26; break;
917
0
    case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: value = 27; break;
918
0
    case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: value = 28; break;
919
0
    case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: value = 29; break;
920
0
    case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: value = 30; break;
921
0
    // ECDH key exchange
922
0
    case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: value = 41; break;
923
0
    case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: value = 42; break;
924
0
    case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: value = 43; break;
925
0
    case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: value = 44; break;
926
0
    case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 45; break;
927
0
    case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: value = 46; break;
928
0
    // RSA key exchange
929
0
    case TLS_RSA_WITH_AES_128_CBC_SHA: value = 61; break;
930
0
    case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 62; break;
931
0
    case TLS_RSA_WITH_AES_256_CBC_SHA: value = 63; break;
932
0
    case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 64; break;
933
0
    case SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA: value = 65; break;
934
0
    case TLS_RSA_WITH_3DES_EDE_CBC_SHA: value = 66; break;
935
0
    case TLS_RSA_WITH_SEED_CBC_SHA: value = 67; break;
936
0
    // TLS 1.3 PSK resumption
937
0
    case TLS_AES_128_GCM_SHA256: value = 70; break;
938
0
    case TLS_CHACHA20_POLY1305_SHA256: value = 71; break;
939
0
    case TLS_AES_256_GCM_SHA384: value = 72; break;
940
0
    // unknown
941
0
    default:
942
0
      value = 0;
943
0
      break;
944
0
  }
945
0
  MOZ_ASSERT(value != 0);
946
0
  Telemetry::Accumulate(probe, value);
947
0
}
948
949
// In the case of session resumption, the AuthCertificate hook has been bypassed
950
// (because we've previously successfully connected to our peer). That being the
951
// case, we unfortunately don't know what the verified certificate chain was, if
952
// the peer's server certificate verified as extended validation, or what its CT
953
// status is (if enabled). To address this, we attempt to build a certificate
954
// chain here using as much of the original context as possible (e.g. stapled
955
// OCSP responses, SCTs, the hostname, the first party domain, etc.). Note that
956
// because we are on the socket thread, this must not cause any network
957
// requests, hence the use of FLAG_LOCAL_ONLY.
958
static void
959
RebuildVerifiedCertificateInformation(PRFileDesc* fd,
960
                                      nsNSSSocketInfo* infoObject)
961
0
{
962
0
  MOZ_ASSERT(fd);
963
0
  MOZ_ASSERT(infoObject);
964
0
965
0
  if (!fd || !infoObject) {
966
0
    return;
967
0
  }
968
0
969
0
  UniqueCERTCertificate cert(SSL_PeerCertificate(fd));
970
0
  MOZ_ASSERT(cert, "SSL_PeerCertificate failed in TLS handshake callback?");
971
0
  if (!cert) {
972
0
    return;
973
0
  }
974
0
975
0
  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
976
0
  MOZ_ASSERT(certVerifier,
977
0
             "Certificate verifier uninitialized in TLS handshake callback?");
978
0
  if (!certVerifier) {
979
0
    return;
980
0
  }
981
0
982
0
  // We don't own these pointers.
983
0
  const SECItemArray* stapledOCSPResponses = SSL_PeerStapledOCSPResponses(fd);
984
0
  const SECItem* stapledOCSPResponse = nullptr;
985
0
  // we currently only support single stapled responses
986
0
  if (stapledOCSPResponses && stapledOCSPResponses->len == 1) {
987
0
    stapledOCSPResponse = &stapledOCSPResponses->items[0];
988
0
  }
989
0
  const SECItem* sctsFromTLSExtension = SSL_PeerSignedCertTimestamps(fd);
990
0
  if (sctsFromTLSExtension && sctsFromTLSExtension->len == 0) {
991
0
    // SSL_PeerSignedCertTimestamps returns null on error and empty item
992
0
    // when no extension was returned by the server. We always use null when
993
0
    // no extension was received (for whatever reason), ignoring errors.
994
0
    sctsFromTLSExtension = nullptr;
995
0
  }
996
0
997
0
  int flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY;
998
0
  if (!infoObject->SharedState().IsOCSPStaplingEnabled() ||
999
0
      !infoObject->SharedState().IsOCSPMustStapleEnabled()) {
1000
0
    flags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST;
1001
0
  }
1002
0
1003
0
  SECOidTag evOidPolicy;
1004
0
  CertificateTransparencyInfo certificateTransparencyInfo;
1005
0
  UniqueCERTCertList builtChain;
1006
0
  const bool saveIntermediates = false;
1007
0
  mozilla::pkix::Result rv = certVerifier->VerifySSLServerCert(
1008
0
    cert,
1009
0
    stapledOCSPResponse,
1010
0
    sctsFromTLSExtension,
1011
0
    mozilla::pkix::Now(),
1012
0
    infoObject,
1013
0
    infoObject->GetHostName(),
1014
0
    builtChain,
1015
0
    saveIntermediates,
1016
0
    flags,
1017
0
    infoObject->GetOriginAttributes(),
1018
0
    &evOidPolicy,
1019
0
    nullptr, // OCSP stapling telemetry
1020
0
    nullptr, // key size telemetry
1021
0
    nullptr, // SHA-1 telemetry
1022
0
    nullptr, // pinning telemetry
1023
0
    &certificateTransparencyInfo);
1024
0
1025
0
  if (rv != Success) {
1026
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1027
0
            ("HandshakeCallback: couldn't rebuild verified certificate info"));
1028
0
  }
1029
0
1030
0
  RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(cert.get()));
1031
0
  if (rv == Success && evOidPolicy != SEC_OID_UNKNOWN) {
1032
0
    infoObject->SetCertificateTransparencyInfo(certificateTransparencyInfo);
1033
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1034
0
            ("HandshakeCallback using NEW cert %p (is EV)", nssc.get()));
1035
0
    infoObject->SetServerCert(nssc, EVStatus::EV);
1036
0
  } else {
1037
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1038
0
            ("HandshakeCallback using NEW cert %p (is not EV)", nssc.get()));
1039
0
    infoObject->SetServerCert(nssc, EVStatus::NotEV);
1040
0
  }
1041
0
1042
0
  if (rv == Success) {
1043
0
    infoObject->SetCertificateTransparencyInfo(certificateTransparencyInfo);
1044
0
    infoObject->SetSucceededCertChain(std::move(builtChain));
1045
0
  }
1046
0
}
1047
1048
static nsresult
1049
IsCertificateDistrustImminent(nsIX509CertList* aCertList,
1050
0
                              /* out */ bool& isDistrusted) {
1051
0
  if (!aCertList) {
1052
0
    return NS_ERROR_INVALID_POINTER;
1053
0
  }
1054
0
1055
0
  nsCOMPtr<nsIX509Cert> rootCert;
1056
0
  nsCOMPtr<nsIX509CertList> intCerts;
1057
0
  nsCOMPtr<nsIX509Cert> eeCert;
1058
0
1059
0
  RefPtr<nsNSSCertList> certList = aCertList->GetCertList();
1060
0
  nsresult rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
1061
0
  if (NS_FAILED(rv)) {
1062
0
    return rv;
1063
0
  }
1064
0
1065
0
  // Check the test certificate condition first; this is a special certificate
1066
0
  // that gets the 'imminent distrust' treatment; this is so that the distrust
1067
0
  // UX code does not become stale, as it will need regular use. See Bug 1409257
1068
0
  // for context. Please do not remove this when adjusting the rest of the
1069
0
  // method.
1070
0
  UniqueCERTCertificate nssEECert(eeCert->GetCert());
1071
0
  if (!nssEECert) {
1072
0
    return NS_ERROR_FAILURE;
1073
0
  }
1074
0
  isDistrusted = CertDNIsInList(nssEECert.get(),
1075
0
                                TestImminentDistrustEndEntityDNs);
1076
0
  if (isDistrusted) {
1077
0
    // Exit early
1078
0
    return NS_OK;
1079
0
  }
1080
0
1081
0
  UniqueCERTCertificate nssRootCert(rootCert->GetCert());
1082
0
  if (!nssRootCert) {
1083
0
    return NS_ERROR_FAILURE;
1084
0
  }
1085
0
1086
0
  // Proceed with the Symantec imminent distrust algorithm. This algorithm is
1087
0
  // to be removed in Firefox 63, when the validity period check will also be
1088
0
  // removed from the code in NSSCertDBTrustDomain.
1089
0
  if (CertDNIsInList(nssRootCert.get(), RootSymantecDNs)) {
1090
0
    static const PRTime NULL_TIME = 0;
1091
0
1092
0
    rv = CheckForSymantecDistrust(intCerts, eeCert, NULL_TIME,
1093
0
                                  RootAppleAndGoogleSPKIs, isDistrusted);
1094
0
    if (NS_FAILED(rv)) {
1095
0
      return rv;
1096
0
    }
1097
0
  }
1098
0
  return NS_OK;
1099
0
}
1100
1101
0
void HandshakeCallback(PRFileDesc* fd, void* client_data) {
1102
0
  SECStatus rv;
1103
0
1104
0
  nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
1105
0
1106
0
  // Do the bookkeeping that needs to be done after the
1107
0
  // server's ServerHello...ServerHelloDone have been processed, but that doesn't
1108
0
  // need the handshake to be completed.
1109
0
  PreliminaryHandshakeDone(fd);
1110
0
1111
0
  nsSSLIOLayerHelpers& ioLayerHelpers
1112
0
    = infoObject->SharedState().IOLayerHelpers();
1113
0
1114
0
  SSLVersionRange versions(infoObject->GetTLSVersionRange());
1115
0
1116
0
  MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1117
0
         ("[%p] HandshakeCallback: succeeded using TLS version range (0x%04x,0x%04x)\n",
1118
0
          fd, static_cast<unsigned int>(versions.min),
1119
0
              static_cast<unsigned int>(versions.max)));
1120
0
1121
0
  // If the handshake completed, then we know the site is TLS tolerant
1122
0
  ioLayerHelpers.rememberTolerantAtVersion(infoObject->GetHostName(),
1123
0
                                           infoObject->GetPort(),
1124
0
                                           versions.max);
1125
0
1126
0
  SSLChannelInfo channelInfo;
1127
0
  rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
1128
0
  MOZ_ASSERT(rv == SECSuccess);
1129
0
  if (rv == SECSuccess) {
1130
0
    // Get the protocol version for telemetry
1131
0
    // 1=tls1, 2=tls1.1, 3=tls1.2
1132
0
    unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
1133
0
    MOZ_ASSERT(versionEnum > 0);
1134
0
    Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
1135
0
    AccumulateCipherSuite(
1136
0
      infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL
1137
0
                                    : Telemetry::SSL_CIPHER_SUITE_RESUMED,
1138
0
      channelInfo);
1139
0
1140
0
    SSLCipherSuiteInfo cipherInfo;
1141
0
    rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
1142
0
                                sizeof cipherInfo);
1143
0
    MOZ_ASSERT(rv == SECSuccess);
1144
0
    if (rv == SECSuccess) {
1145
0
      // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
1146
0
      Telemetry::Accumulate(
1147
0
        infoObject->IsFullHandshake()
1148
0
          ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
1149
0
          : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
1150
0
        channelInfo.keaType);
1151
0
1152
0
      MOZ_ASSERT(infoObject->GetKEAUsed() == channelInfo.keaType);
1153
0
1154
0
      if (infoObject->IsFullHandshake()) {
1155
0
        switch (channelInfo.keaType) {
1156
0
          case ssl_kea_rsa:
1157
0
            AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
1158
0
                                    channelInfo.keaKeyBits);
1159
0
            break;
1160
0
          case ssl_kea_dh:
1161
0
            AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL,
1162
0
                                    channelInfo.keaKeyBits);
1163
0
            break;
1164
0
          case ssl_kea_ecdh:
1165
0
            AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL,
1166
0
                               channelInfo.keaKeyBits);
1167
0
            break;
1168
0
          default:
1169
0
            MOZ_CRASH("impossible KEA");
1170
0
            break;
1171
0
        }
1172
0
1173
0
        Telemetry::Accumulate(Telemetry::SSL_AUTH_ALGORITHM_FULL,
1174
0
                              channelInfo.authType);
1175
0
1176
0
        // RSA key exchange doesn't use a signature for auth.
1177
0
        if (channelInfo.keaType != ssl_kea_rsa) {
1178
0
          switch (channelInfo.authType) {
1179
0
            case ssl_auth_rsa:
1180
0
            case ssl_auth_rsa_sign:
1181
0
              AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
1182
0
                                      channelInfo.authKeyBits);
1183
0
              break;
1184
0
            case ssl_auth_ecdsa:
1185
0
              AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL,
1186
0
                                 channelInfo.authKeyBits);
1187
0
              break;
1188
0
            default:
1189
0
              MOZ_CRASH("impossible auth algorithm");
1190
0
              break;
1191
0
          }
1192
0
        }
1193
0
      }
1194
0
1195
0
      Telemetry::Accumulate(
1196
0
          infoObject->IsFullHandshake()
1197
0
            ? Telemetry::SSL_SYMMETRIC_CIPHER_FULL
1198
0
            : Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED,
1199
0
          cipherInfo.symCipher);
1200
0
    }
1201
0
  }
1202
0
1203
0
  PRBool siteSupportsSafeRenego;
1204
0
  if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_3) {
1205
0
    rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
1206
0
                                          &siteSupportsSafeRenego);
1207
0
    MOZ_ASSERT(rv == SECSuccess);
1208
0
    if (rv != SECSuccess) {
1209
0
      siteSupportsSafeRenego = false;
1210
0
    }
1211
0
  } else {
1212
0
    // TLS 1.3 dropped support for renegotiation.
1213
0
    siteSupportsSafeRenego = true;
1214
0
  }
1215
0
  bool renegotiationUnsafe = !siteSupportsSafeRenego &&
1216
0
                             ioLayerHelpers.treatUnsafeNegotiationAsBroken();
1217
0
1218
0
1219
0
  RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject);
1220
0
1221
0
  uint32_t state;
1222
0
  if (renegotiationUnsafe) {
1223
0
    state = nsIWebProgressListener::STATE_IS_BROKEN;
1224
0
  } else {
1225
0
    state = nsIWebProgressListener::STATE_IS_SECURE |
1226
0
            nsIWebProgressListener::STATE_SECURE_HIGH;
1227
0
    SSLVersionRange defVersion;
1228
0
    rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion);
1229
0
    if (rv == SECSuccess && versions.max >= defVersion.max) {
1230
0
      // we know this site no longer requires a version fallback
1231
0
      ioLayerHelpers.removeInsecureFallbackSite(infoObject->GetHostName(),
1232
0
                                                infoObject->GetPort());
1233
0
    }
1234
0
  }
1235
0
1236
0
  if (infoObject->HasServerCert()) {
1237
0
    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1238
0
           ("HandshakeCallback KEEPING existing cert\n"));
1239
0
  } else {
1240
0
    RebuildVerifiedCertificateInformation(fd, infoObject);
1241
0
  }
1242
0
1243
0
  nsCOMPtr<nsIX509CertList> succeededCertChain;
1244
0
  // This always returns NS_OK, but the list could be empty. This is a
1245
0
  // best-effort check for now. Bug 731478 will reduce the incidence of empty
1246
0
  // succeeded cert chains through better caching.
1247
0
  Unused << infoObject->GetSucceededCertChain(
1248
0
                          getter_AddRefs(succeededCertChain));
1249
0
  bool distrustImminent;
1250
0
  nsresult srv = IsCertificateDistrustImminent(succeededCertChain,
1251
0
                                               distrustImminent);
1252
0
  if (NS_SUCCEEDED(srv) && distrustImminent) {
1253
0
    state |= nsIWebProgressListener::STATE_CERT_DISTRUST_IMMINENT;
1254
0
  }
1255
0
1256
0
  bool domainMismatch;
1257
0
  bool untrusted;
1258
0
  bool notValidAtThisTime;
1259
0
  // These all return NS_OK, so don't even bother checking the return values.
1260
0
  Unused << infoObject->GetIsDomainMismatch(&domainMismatch);
1261
0
  Unused << infoObject->GetIsUntrusted(&untrusted);
1262
0
  Unused << infoObject->GetIsNotValidAtThisTime(&notValidAtThisTime);
1263
0
  // If we're here, the TLS handshake has succeeded. Thus if any of these
1264
0
  // booleans are true, the user has added an override for a certificate error.
1265
0
  if (domainMismatch || untrusted || notValidAtThisTime) {
1266
0
    state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
1267
0
  }
1268
0
1269
0
  infoObject->SetSecurityState(state);
1270
0
1271
0
  // XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
1272
0
  // we should set a flag on the channel that higher (UI) level code can check
1273
0
  // to log the warning. In particular, these warnings should go to the web
1274
0
  // console instead of to the error console. Also, the warning is not
1275
0
  // localized.
1276
0
  if (!siteSupportsSafeRenego) {
1277
0
    NS_ConvertASCIItoUTF16 msg(infoObject->GetHostName());
1278
0
    msg.AppendLiteral(" : server does not support RFC 5746, see CVE-2009-3555");
1279
0
1280
0
    nsContentUtils::LogSimpleConsoleError(msg, "SSL",
1281
0
                                          !!infoObject->GetOriginAttributes().mPrivateBrowsingId);
1282
0
  }
1283
0
1284
0
  infoObject->NoteTimeUntilReady();
1285
0
  infoObject->SetHandshakeCompleted();
1286
0
}