Source code

Revision control

Other Tools

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