Bug 1928997: Update tabs icon in Unified Search popup r=desktop-theme-reviewers,daleh...
[gecko.git] / security / manager / ssl / nsNSSCallbacks.cpp
blob1abe27c014837259e3cf9f1deb9f6662553873f5
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
7 #include "nsNSSCallbacks.h"
9 #include "NSSSocketControl.h"
10 #include "PSMRunnable.h"
11 #include "ScopedNSSTypes.h"
12 #include "SharedCertVerifier.h"
13 #include "mozilla/ArrayUtils.h"
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Casting.h"
16 #include "mozilla/Logging.h"
17 #include "mozilla/RefPtr.h"
18 #include "mozilla/ScopeExit.h"
19 #include "mozilla/Span.h"
20 #include "mozilla/SpinEventLoopUntil.h"
21 #include "mozilla/StaticPrefs_security.h"
22 #include "mozilla/Telemetry.h"
23 #include "mozilla/Unused.h"
24 #include "mozilla/glean/GleanMetrics.h"
25 #include "mozilla/intl/Localization.h"
26 #include "nsContentUtils.h"
27 #include "nsIChannel.h"
28 #include "nsIHttpChannel.h"
29 #include "nsIHttpChannelInternal.h"
30 #include "nsIPrompt.h"
31 #include "nsIProtocolProxyService.h"
32 #include "nsISupportsPriority.h"
33 #include "nsIStreamLoader.h"
34 #include "nsIUploadChannel.h"
35 #include "nsIWebProgressListener.h"
36 #include "nsNSSCertHelper.h"
37 #include "nsNSSCertificate.h"
38 #include "nsNSSComponent.h"
39 #include "nsNSSHelper.h"
40 #include "nsNSSIOLayer.h"
41 #include "nsNetUtil.h"
42 #include "nsProxyRelease.h"
43 #include "nsStringStream.h"
44 #include "mozpkix/pkixtypes.h"
45 #include "ssl.h"
46 #include "sslproto.h"
47 #include "SSLTokensCache.h"
49 #include "TrustOverrideUtils.h"
50 #include "TrustOverride-SymantecData.inc"
51 #include "TrustOverride-AppleGoogleDigiCertData.inc"
53 using namespace mozilla;
54 using namespace mozilla::pkix;
55 using namespace mozilla::psm;
57 extern LazyLogModule gPIPNSSLog;
59 namespace {
61 // Bits in bit mask for SSL_REASONS_FOR_NOT_FALSE_STARTING telemetry probe
62 // These bits are numbered so that the least subtle issues have higher values.
63 // This should make it easier for us to interpret the results.
64 const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4;
65 const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2;
66 const uint32_t KEA_NOT_SUPPORTED = 1;
68 } // namespace
70 class OCSPRequest final : public nsIStreamLoaderObserver, public nsIRunnable {
71 public:
72 OCSPRequest(const nsACString& aiaLocation,
73 const OriginAttributes& originAttributes,
74 const uint8_t (&ocspRequest)[OCSP_REQUEST_MAX_LENGTH],
75 size_t ocspRequestLength, TimeDuration timeout);
77 NS_DECL_THREADSAFE_ISUPPORTS
78 NS_DECL_NSISTREAMLOADEROBSERVER
79 NS_DECL_NSIRUNNABLE
81 nsresult DispatchToMainThreadAndWait();
82 nsresult GetResponse(/*out*/ Vector<uint8_t>& response);
84 private:
85 ~OCSPRequest() = default;
87 static void OnTimeout(nsITimer* timer, void* closure);
88 nsresult NotifyDone(nsresult rv, MonitorAutoLock& proofOfLock);
90 // mMonitor provides the memory barrier protecting these member variables.
91 // What happens is the originating thread creates an OCSPRequest object with
92 // the information necessary to perform an OCSP request. It sends the object
93 // to the main thread and waits on the monitor for the operation to complete.
94 // On the main thread, a channel is set up to perform the request. This gets
95 // dispatched to necko. At the same time, a timeout timer is initialized. If
96 // the necko request completes, the response data is filled out, mNotifiedDone
97 // is set to true, and the monitor is notified. The original thread then wakes
98 // up and continues with the results that have been filled out. If the request
99 // times out, again the response data is filled out, mNotifiedDone is set to
100 // true, and the monitor is notified. The first of these two events wins. That
101 // is, if the timeout timer fires but the request completes shortly after, the
102 // caller will see the request as having timed out.
103 // When the request completes (i.e. OnStreamComplete runs), the timer will be
104 // cancelled. This is how we know the closure in OnTimeout is valid. If the
105 // timer fires before OnStreamComplete runs, it should be safe to not cancel
106 // the request because necko has a strong reference to it.
107 Monitor mMonitor MOZ_UNANNOTATED;
108 bool mNotifiedDone;
109 nsCOMPtr<nsIStreamLoader> mLoader;
110 const nsCString mAIALocation;
111 const OriginAttributes mOriginAttributes;
112 const mozilla::Span<const char> mPOSTData;
113 const TimeDuration mTimeout;
114 nsCOMPtr<nsITimer> mTimeoutTimer;
115 TimeStamp mStartTime;
116 nsresult mResponseResult;
117 Vector<uint8_t> mResponseBytes;
120 NS_IMPL_ISUPPORTS(OCSPRequest, nsIStreamLoaderObserver, nsIRunnable)
122 OCSPRequest::OCSPRequest(const nsACString& aiaLocation,
123 const OriginAttributes& originAttributes,
124 const uint8_t (&ocspRequest)[OCSP_REQUEST_MAX_LENGTH],
125 size_t ocspRequestLength, TimeDuration timeout)
126 : mMonitor("OCSPRequest.mMonitor"),
127 mNotifiedDone(false),
128 mLoader(nullptr),
129 mAIALocation(aiaLocation),
130 mOriginAttributes(originAttributes),
131 mPOSTData(reinterpret_cast<const char*>(ocspRequest), ocspRequestLength),
132 mTimeout(timeout),
133 mTimeoutTimer(nullptr),
134 mResponseResult(NS_ERROR_FAILURE) {
135 MOZ_ASSERT(ocspRequestLength <= OCSP_REQUEST_MAX_LENGTH);
138 nsresult OCSPRequest::DispatchToMainThreadAndWait() {
139 MOZ_ASSERT(!NS_IsMainThread());
140 if (NS_IsMainThread()) {
141 return NS_ERROR_FAILURE;
144 MonitorAutoLock lock(mMonitor);
145 nsresult rv = NS_DispatchToMainThread(this);
146 if (NS_FAILED(rv)) {
147 return rv;
149 while (!mNotifiedDone) {
150 lock.Wait();
153 // CERT_VALIDATION_HTTP_REQUEST_RESULT:
154 // 0: request timed out
155 // 1: request succeeded
156 // 2: request failed
157 // 3: internal error
158 // If mStartTime was never set, we consider this an internal error.
159 // Otherwise, we managed to at least send the request.
160 if (mStartTime.IsNull()) {
161 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 3);
162 } else if (mResponseResult == NS_ERROR_NET_TIMEOUT) {
163 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 0);
164 mozilla::glean::ocsp_request_time::cancel.AccumulateRawDuration(
165 TimeStamp::Now() - mStartTime);
166 } else if (NS_SUCCEEDED(mResponseResult)) {
167 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 1);
168 mozilla::glean::ocsp_request_time::success.AccumulateRawDuration(
169 TimeStamp::Now() - mStartTime);
170 } else {
171 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 2);
172 mozilla::glean::ocsp_request_time::failure.AccumulateRawDuration(
173 TimeStamp::Now() - mStartTime);
175 return rv;
178 nsresult OCSPRequest::GetResponse(/*out*/ Vector<uint8_t>& response) {
179 MOZ_ASSERT(!NS_IsMainThread());
180 if (NS_IsMainThread()) {
181 return NS_ERROR_FAILURE;
184 MonitorAutoLock lock(mMonitor);
185 if (!mNotifiedDone) {
186 return NS_ERROR_IN_PROGRESS;
188 if (NS_FAILED(mResponseResult)) {
189 return mResponseResult;
191 response.clear();
192 if (!response.append(mResponseBytes.begin(), mResponseBytes.length())) {
193 return NS_ERROR_OUT_OF_MEMORY;
195 return NS_OK;
198 static constexpr auto OCSP_REQUEST_MIME_TYPE = "application/ocsp-request"_ns;
199 static constexpr auto OCSP_REQUEST_METHOD = "POST"_ns;
201 NS_IMETHODIMP
202 OCSPRequest::Run() {
203 MOZ_ASSERT(NS_IsMainThread());
204 if (!NS_IsMainThread()) {
205 return NS_ERROR_FAILURE;
208 MonitorAutoLock lock(mMonitor);
210 nsCOMPtr<nsIIOService> ios = do_GetIOService();
211 if (!ios) {
212 return NotifyDone(NS_ERROR_FAILURE, lock);
215 nsCOMPtr<nsIURI> uri;
216 nsresult rv = NS_NewURI(getter_AddRefs(uri), mAIALocation);
217 if (NS_FAILED(rv)) {
218 return NotifyDone(NS_ERROR_MALFORMED_URI, lock);
220 nsAutoCString scheme;
221 rv = uri->GetScheme(scheme);
222 if (NS_FAILED(rv)) {
223 return NotifyDone(rv, lock);
225 if (!scheme.LowerCaseEqualsLiteral("http")) {
226 return NotifyDone(NS_ERROR_MALFORMED_URI, lock);
229 // See bug 1219935.
230 // We should not send OCSP request if the PAC is still loading.
231 nsCOMPtr<nsIProtocolProxyService> pps =
232 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
233 if (NS_FAILED(rv)) {
234 return NotifyDone(rv, lock);
237 if (pps->GetIsPACLoading()) {
238 return NotifyDone(NS_ERROR_FAILURE, lock);
241 nsCOMPtr<nsIChannel> channel;
242 rv = ios->NewChannel(mAIALocation, nullptr, nullptr,
243 nullptr, // aLoadingNode
244 nsContentUtils::GetSystemPrincipal(),
245 nullptr, // aTriggeringPrincipal
246 nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
247 nsIContentPolicy::TYPE_OTHER, getter_AddRefs(channel));
248 if (NS_FAILED(rv)) {
249 return NotifyDone(rv, lock);
252 // Security operations scheduled through normal HTTP channels are given
253 // high priority to accommodate real time OCSP transactions.
254 nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(channel);
255 if (priorityChannel) {
256 priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
259 channel->SetLoadFlags(
260 nsIRequest::LOAD_ANONYMOUS | nsIRequest::LOAD_BYPASS_CACHE |
261 nsIRequest::INHIBIT_CACHING | nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
262 nsIChannel::LOAD_BYPASS_URL_CLASSIFIER);
264 nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
266 // Prevent HTTPS-Only Mode from upgrading the OCSP request.
267 uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
268 httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_EXEMPT;
269 loadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
271 // allow deprecated HTTP request from SystemPrincipal
272 loadInfo->SetAllowDeprecatedSystemRequests(true);
274 // For OCSP requests, only the first party domain and private browsing id
275 // aspects of origin attributes are used. This means that:
276 // a) if first party isolation is enabled, OCSP requests will be isolated
277 // according to the first party domain of the original https request
278 // b) OCSP requests are shared across different containers as long as first
279 // party isolation is not enabled and none of the containers are in private
280 // browsing mode.
281 if (mOriginAttributes != OriginAttributes()) {
282 OriginAttributes attrs;
283 attrs.mFirstPartyDomain = mOriginAttributes.mFirstPartyDomain;
284 attrs.mPrivateBrowsingId = mOriginAttributes.mPrivateBrowsingId;
286 rv = loadInfo->SetOriginAttributes(attrs);
287 if (NS_FAILED(rv)) {
288 return NotifyDone(rv, lock);
292 nsCOMPtr<nsIInputStream> uploadStream;
293 rv = NS_NewByteInputStream(getter_AddRefs(uploadStream), mPOSTData,
294 NS_ASSIGNMENT_COPY);
295 if (NS_FAILED(rv)) {
296 return NotifyDone(rv, lock);
298 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(channel));
299 if (!uploadChannel) {
300 return NotifyDone(NS_ERROR_FAILURE, lock);
302 rv = uploadChannel->SetUploadStream(uploadStream, OCSP_REQUEST_MIME_TYPE, -1);
303 if (NS_FAILED(rv)) {
304 return NotifyDone(rv, lock);
306 // Do not use SPDY or HTTP3 for internal security operations. It could result
307 // in the silent upgrade to ssl, which in turn could require an SSL
308 // operation to fulfill something like an OCSP fetch, which is an
309 // endless loop.
310 nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(channel);
311 if (!internalChannel) {
312 return NotifyDone(rv, lock);
314 rv = internalChannel->SetAllowSpdy(false);
315 if (NS_FAILED(rv)) {
316 return NotifyDone(rv, lock);
318 rv = internalChannel->SetAllowHttp3(false);
319 if (NS_FAILED(rv)) {
320 return NotifyDone(rv, lock);
322 rv = internalChannel->SetIsOCSP(true);
323 if (NS_FAILED(rv)) {
324 return NotifyDone(rv, lock);
326 nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(channel);
327 if (!hchan) {
328 return NotifyDone(NS_ERROR_FAILURE, lock);
330 rv = hchan->SetAllowSTS(false);
331 if (NS_FAILED(rv)) {
332 return NotifyDone(rv, lock);
334 rv = hchan->SetRequestMethod(OCSP_REQUEST_METHOD);
335 if (NS_FAILED(rv)) {
336 return NotifyDone(rv, lock);
339 rv = NS_NewStreamLoader(getter_AddRefs(mLoader), this);
340 if (NS_FAILED(rv)) {
341 return NotifyDone(rv, lock);
344 rv = NS_NewTimerWithFuncCallback(
345 getter_AddRefs(mTimeoutTimer), OCSPRequest::OnTimeout, this,
346 mTimeout.ToMilliseconds(), nsITimer::TYPE_ONE_SHOT, "OCSPRequest::Run");
347 if (NS_FAILED(rv)) {
348 return NotifyDone(rv, lock);
350 rv = hchan->AsyncOpen(this->mLoader);
351 if (NS_FAILED(rv)) {
352 return NotifyDone(rv, lock);
354 mStartTime = TimeStamp::Now();
355 return NS_OK;
358 nsresult OCSPRequest::NotifyDone(nsresult rv, MonitorAutoLock& lock) {
359 MOZ_ASSERT(NS_IsMainThread());
360 if (!NS_IsMainThread()) {
361 return NS_ERROR_FAILURE;
364 if (mNotifiedDone) {
365 return mResponseResult;
367 mLoader = nullptr;
368 mResponseResult = rv;
369 if (mTimeoutTimer) {
370 Unused << mTimeoutTimer->Cancel();
372 mNotifiedDone = true;
373 lock.Notify();
374 return rv;
377 NS_IMETHODIMP
378 OCSPRequest::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
379 nsresult aStatus, uint32_t responseLen,
380 const uint8_t* responseBytes) {
381 MOZ_ASSERT(NS_IsMainThread());
382 if (!NS_IsMainThread()) {
383 return NS_ERROR_FAILURE;
386 MonitorAutoLock lock(mMonitor);
388 nsCOMPtr<nsIRequest> req;
389 nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
390 if (NS_FAILED(rv)) {
391 return NotifyDone(rv, lock);
394 if (NS_FAILED(aStatus)) {
395 return NotifyDone(aStatus, lock);
398 nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(req);
399 if (!hchan) {
400 return NotifyDone(NS_ERROR_FAILURE, lock);
403 bool requestSucceeded;
404 rv = hchan->GetRequestSucceeded(&requestSucceeded);
405 if (NS_FAILED(rv)) {
406 return NotifyDone(rv, lock);
408 if (!requestSucceeded) {
409 return NotifyDone(NS_ERROR_FAILURE, lock);
412 unsigned int rcode;
413 rv = hchan->GetResponseStatus(&rcode);
414 if (NS_FAILED(rv)) {
415 return NotifyDone(rv, lock);
417 if (rcode != 200) {
418 return NotifyDone(NS_ERROR_FAILURE, lock);
421 mResponseBytes.clear();
422 if (!mResponseBytes.append(responseBytes, responseLen)) {
423 return NotifyDone(NS_ERROR_OUT_OF_MEMORY, lock);
425 mResponseResult = aStatus;
427 return NotifyDone(NS_OK, lock);
430 void OCSPRequest::OnTimeout(nsITimer* timer, void* closure) {
431 MOZ_ASSERT(NS_IsMainThread());
432 if (!NS_IsMainThread()) {
433 return;
436 // We know the OCSPRequest is still alive because if the request had completed
437 // (i.e. OnStreamComplete ran), the timer would have been cancelled in
438 // NotifyDone.
439 OCSPRequest* self = static_cast<OCSPRequest*>(closure);
440 MonitorAutoLock lock(self->mMonitor);
441 self->mTimeoutTimer = nullptr;
442 self->NotifyDone(NS_ERROR_NET_TIMEOUT, lock);
445 mozilla::pkix::Result DoOCSPRequest(
446 const nsCString& aiaLocation, const OriginAttributes& originAttributes,
447 uint8_t (&ocspRequest)[OCSP_REQUEST_MAX_LENGTH], size_t ocspRequestLength,
448 TimeDuration timeout, /*out*/ Vector<uint8_t>& result) {
449 MOZ_ASSERT(!NS_IsMainThread());
450 if (NS_IsMainThread()) {
451 return mozilla::pkix::Result::ERROR_OCSP_UNKNOWN_CERT;
454 if (ocspRequestLength > OCSP_REQUEST_MAX_LENGTH) {
455 return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
458 result.clear();
459 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
460 ("DoOCSPRequest to '%s'", aiaLocation.get()));
462 nsCOMPtr<nsIEventTarget> sts =
463 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID);
464 MOZ_ASSERT(sts);
465 if (!sts) {
466 return mozilla::pkix::Result::FATAL_ERROR_INVALID_STATE;
468 bool onSTSThread;
469 nsresult rv = sts->IsOnCurrentThread(&onSTSThread);
470 if (NS_FAILED(rv)) {
471 return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
473 MOZ_ASSERT(!onSTSThread);
474 if (onSTSThread) {
475 return mozilla::pkix::Result::FATAL_ERROR_INVALID_STATE;
478 RefPtr<OCSPRequest> request(new OCSPRequest(
479 aiaLocation, originAttributes, ocspRequest, ocspRequestLength, timeout));
480 rv = request->DispatchToMainThreadAndWait();
481 if (NS_FAILED(rv)) {
482 return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
484 rv = request->GetResponse(result);
485 if (NS_FAILED(rv)) {
486 if (rv == NS_ERROR_MALFORMED_URI) {
487 return mozilla::pkix::Result::ERROR_CERT_BAD_ACCESS_LOCATION;
489 return mozilla::pkix::Result::ERROR_OCSP_SERVER_ERROR;
491 return Success;
494 static char* ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIPrompt* prompt) {
495 MOZ_ASSERT(NS_IsMainThread());
496 MOZ_ASSERT(slot);
497 MOZ_ASSERT(prompt);
498 if (!NS_IsMainThread() || !slot || !prompt) {
499 return nullptr;
502 // Dispatch a background task to (eventually) call C_Login. The call will
503 // block until the protected authentication succeeds or fails.
504 Atomic<bool> done;
505 Atomic<SECStatus> result;
506 nsresult rv =
507 NS_DispatchBackgroundTask(NS_NewRunnableFunction(__func__, [&]() mutable {
508 result = PK11_CheckUserPassword(slot, nullptr);
509 done = true;
510 }));
511 if (NS_FAILED(rv)) {
512 return nullptr;
515 nsTArray<nsCString> resIds = {
516 "security/pippki/pippki.ftl"_ns,
518 RefPtr<mozilla::intl::Localization> l10n =
519 mozilla::intl::Localization::Create(resIds, true);
520 auto l10nId = "protected-auth-alert"_ns;
521 auto l10nArgs = mozilla::dom::Optional<intl::L10nArgs>();
522 l10nArgs.Construct();
523 auto dirArg = l10nArgs.Value().Entries().AppendElement();
524 dirArg->mKey = "tokenName"_ns;
525 dirArg->mValue.SetValue().SetAsUTF8String().Assign(PK11_GetTokenName(slot));
526 nsAutoCString promptString;
527 ErrorResult errorResult;
528 l10n->FormatValueSync(l10nId, l10nArgs, promptString, errorResult);
529 if (NS_FAILED(errorResult.StealNSResult())) {
530 return nullptr;
532 rv = prompt->Alert(nullptr, NS_ConvertUTF8toUTF16(promptString).get());
533 if (NS_FAILED(rv)) {
534 return nullptr;
537 MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
538 "ShowProtectedAuthPrompt"_ns, [&]() { return static_cast<bool>(done); }));
540 switch (result) {
541 case SECSuccess:
542 return ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
543 case SECWouldBlock:
544 return ToNewCString(nsDependentCString(PK11_PW_RETRY));
545 default:
546 return nullptr;
550 class PK11PasswordPromptRunnable : public SyncRunnableBase {
551 public:
552 PK11PasswordPromptRunnable(PK11SlotInfo* slot, nsIInterfaceRequestor* ir)
553 : mResult(nullptr), mSlot(slot), mIR(ir) {}
554 virtual ~PK11PasswordPromptRunnable() = default;
556 char* mResult; // out
557 virtual void RunOnTargetThread() override;
559 private:
560 static bool mRunning;
562 PK11SlotInfo* mSlot;
563 nsIInterfaceRequestor* mIR;
566 bool PK11PasswordPromptRunnable::mRunning = false;
568 void PK11PasswordPromptRunnable::RunOnTargetThread() {
569 MOZ_ASSERT(NS_IsMainThread());
570 if (!NS_IsMainThread()) {
571 return;
574 // If we've reentered due to the nested event loop implicit in using
575 // nsIPrompt synchronously (or indeed the explicit nested event loop in the
576 // protected authentication case), bail early, cancelling the password
577 // prompt. This will probably cause the operation that resulted in the prompt
578 // to fail, but this is better than littering the screen with a bunch of
579 // password prompts that the user will probably just cancel anyway.
580 if (mRunning) {
581 return;
583 mRunning = true;
584 auto setRunningToFalseOnExit = MakeScopeExit([&]() { mRunning = false; });
586 nsresult rv;
587 nsCOMPtr<nsIPrompt> prompt;
588 if (!mIR) {
589 rv = nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
590 if (NS_FAILED(rv)) {
591 return;
593 } else {
594 prompt = do_GetInterface(mIR);
595 MOZ_ASSERT(prompt, "Interface requestor should implement nsIPrompt");
598 if (!prompt) {
599 return;
602 if (PK11_ProtectedAuthenticationPath(mSlot)) {
603 mResult = ShowProtectedAuthPrompt(mSlot, prompt);
604 return;
607 nsAutoString promptString;
608 if (PK11_IsInternal(mSlot)) {
609 rv = GetPIPNSSBundleString("CertPasswordPromptDefault", promptString);
610 } else {
611 AutoTArray<nsString, 1> formatStrings = {
612 NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot))};
613 rv = PIPBundleFormatStringFromName("CertPasswordPrompt", formatStrings,
614 promptString);
616 if (NS_FAILED(rv)) {
617 return;
620 nsString password;
621 bool userClickedOK = false;
622 rv = prompt->PromptPassword(nullptr, promptString.get(),
623 getter_Copies(password), &userClickedOK);
624 if (NS_FAILED(rv) || !userClickedOK) {
625 return;
628 mResult = ToNewUTF8String(password);
631 char* PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg) {
632 if (!slot) {
633 return nullptr;
635 RefPtr<PK11PasswordPromptRunnable> runnable(new PK11PasswordPromptRunnable(
636 slot, static_cast<nsIInterfaceRequestor*>(arg)));
637 runnable->DispatchToMainThreadAndWait();
638 return runnable->mResult;
641 nsCString getKeaGroupName(uint32_t aKeaGroup) {
642 nsCString groupName;
643 switch (aKeaGroup) {
644 case ssl_grp_ec_secp256r1:
645 groupName = "P256"_ns;
646 break;
647 case ssl_grp_ec_secp384r1:
648 groupName = "P384"_ns;
649 break;
650 case ssl_grp_ec_secp521r1:
651 groupName = "P521"_ns;
652 break;
653 case ssl_grp_ec_curve25519:
654 groupName = "x25519"_ns;
655 break;
656 case ssl_grp_kem_xyber768d00:
657 groupName = "xyber768d00"_ns;
658 break;
659 case ssl_grp_kem_mlkem768x25519:
660 groupName = "mlkem768x25519"_ns;
661 break;
662 case ssl_grp_ffdhe_2048:
663 groupName = "FF 2048"_ns;
664 break;
665 case ssl_grp_ffdhe_3072:
666 groupName = "FF 3072"_ns;
667 break;
668 case ssl_grp_none:
669 groupName = "none"_ns;
670 break;
671 case ssl_grp_ffdhe_custom:
672 groupName = "custom"_ns;
673 break;
674 // All other groups are not enabled in Firefox. See namedGroups in
675 // nsNSSIOLayer.cpp.
676 default:
677 // This really shouldn't happen!
678 MOZ_ASSERT_UNREACHABLE("Invalid key exchange group.");
679 groupName = "unknown group"_ns;
681 return groupName;
684 nsCString getSignatureName(uint32_t aSignatureScheme) {
685 nsCString signatureName;
686 switch (aSignatureScheme) {
687 case ssl_sig_none:
688 signatureName = "none"_ns;
689 break;
690 case ssl_sig_rsa_pkcs1_sha1:
691 signatureName = "RSA-PKCS1-SHA1"_ns;
692 break;
693 case ssl_sig_rsa_pkcs1_sha256:
694 signatureName = "RSA-PKCS1-SHA256"_ns;
695 break;
696 case ssl_sig_rsa_pkcs1_sha384:
697 signatureName = "RSA-PKCS1-SHA384"_ns;
698 break;
699 case ssl_sig_rsa_pkcs1_sha512:
700 signatureName = "RSA-PKCS1-SHA512"_ns;
701 break;
702 case ssl_sig_ecdsa_secp256r1_sha256:
703 signatureName = "ECDSA-P256-SHA256"_ns;
704 break;
705 case ssl_sig_ecdsa_secp384r1_sha384:
706 signatureName = "ECDSA-P384-SHA384"_ns;
707 break;
708 case ssl_sig_ecdsa_secp521r1_sha512:
709 signatureName = "ECDSA-P521-SHA512"_ns;
710 break;
711 case ssl_sig_rsa_pss_sha256:
712 signatureName = "RSA-PSS-SHA256"_ns;
713 break;
714 case ssl_sig_rsa_pss_sha384:
715 signatureName = "RSA-PSS-SHA384"_ns;
716 break;
717 case ssl_sig_rsa_pss_sha512:
718 signatureName = "RSA-PSS-SHA512"_ns;
719 break;
720 case ssl_sig_ecdsa_sha1:
721 signatureName = "ECDSA-SHA1"_ns;
722 break;
723 case ssl_sig_rsa_pkcs1_sha1md5:
724 signatureName = "RSA-PKCS1-SHA1MD5"_ns;
725 break;
726 // All other groups are not enabled in Firefox. See sEnabledSignatureSchemes
727 // in nsNSSIOLayer.cpp.
728 default:
729 // This really shouldn't happen!
730 MOZ_ASSERT_UNREACHABLE("Invalid signature scheme.");
731 signatureName = "unknown signature"_ns;
733 return signatureName;
736 static void PreliminaryHandshakeDone(PRFileDesc* fd) {
737 NSSSocketControl* socketControl = (NSSSocketControl*)fd->higher->secret;
738 if (!socketControl) {
739 return;
741 if (socketControl->IsPreliminaryHandshakeDone()) {
742 return;
745 SSLChannelInfo channelInfo;
746 if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
747 return;
749 SSLCipherSuiteInfo cipherInfo;
750 if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
751 sizeof(cipherInfo)) != SECSuccess) {
752 return;
754 socketControl->SetPreliminaryHandshakeInfo(channelInfo, cipherInfo);
755 socketControl->SetSSLVersionUsed(channelInfo.protocolVersion);
756 socketControl->SetEarlyDataAccepted(channelInfo.earlyDataAccepted);
757 socketControl->SetKEAUsed(channelInfo.keaType);
758 socketControl->SetKEAKeyBits(channelInfo.keaKeyBits);
759 socketControl->SetMACAlgorithmUsed(cipherInfo.macAlgorithm);
761 // Get the NPN value.
762 SSLNextProtoState state;
763 unsigned char npnbuf[256];
764 unsigned int npnlen;
766 if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen,
767 AssertedCast<unsigned int>(std::size(npnbuf))) ==
768 SECSuccess) {
769 if (state == SSL_NEXT_PROTO_NEGOTIATED ||
770 state == SSL_NEXT_PROTO_SELECTED) {
771 socketControl->SetNegotiatedNPN(
772 BitwiseCast<char*, unsigned char*>(npnbuf), npnlen);
773 } else {
774 socketControl->SetNegotiatedNPN(nullptr, 0);
776 mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE, state);
777 } else {
778 socketControl->SetNegotiatedNPN(nullptr, 0);
781 socketControl->SetPreliminaryHandshakeDone();
784 SECStatus CanFalseStartCallback(PRFileDesc* fd, void* client_data,
785 PRBool* canFalseStart) {
786 *canFalseStart = false;
788 NSSSocketControl* infoObject = (NSSSocketControl*)fd->higher->secret;
789 if (!infoObject) {
790 PR_SetError(PR_INVALID_STATE_ERROR, 0);
791 return SECFailure;
794 infoObject->SetFalseStartCallbackCalled();
796 PreliminaryHandshakeDone(fd);
798 uint32_t reasonsForNotFalseStarting = 0;
800 SSLChannelInfo channelInfo;
801 if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
802 return SECSuccess;
805 SSLCipherSuiteInfo cipherInfo;
806 if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
807 sizeof(cipherInfo)) != SECSuccess) {
808 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
809 ("CanFalseStartCallback [%p] failed - "
810 " KEA %d\n",
811 fd, static_cast<int32_t>(channelInfo.keaType)));
812 return SECSuccess;
815 // Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
816 // TLS 1.3 and later. See Bug 861310 for all the details as to why.
817 if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2) {
818 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
819 ("CanFalseStartCallback [%p] failed - "
820 "SSL Version must be TLS 1.2, was %x\n",
821 fd, static_cast<int32_t>(channelInfo.protocolVersion)));
822 reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE;
825 // See bug 952863 for why ECDHE is allowed, but DHE (and RSA) are not.
826 // Also note that ecdh_hybrid groups are not supported in TLS 1.2 and are out
827 // of scope.
828 if (channelInfo.keaType != ssl_kea_ecdh) {
829 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
830 ("CanFalseStartCallback [%p] failed - "
831 "unsupported KEA %d\n",
832 fd, static_cast<int32_t>(channelInfo.keaType)));
833 reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
836 // Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
837 // mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
838 // design. See bug 1109766 for more details.
839 if (cipherInfo.macAlgorithm != ssl_mac_aead) {
840 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
841 ("CanFalseStartCallback [%p] failed - non-AEAD cipher used, %d, "
842 "is not supported with False Start.\n",
843 fd, static_cast<int32_t>(cipherInfo.symCipher)));
844 reasonsForNotFalseStarting |= POSSIBLE_CIPHER_SUITE_DOWNGRADE;
847 // XXX: An attacker can choose which protocols are advertised in the
848 // NPN extension. TODO(Bug 861311): We should restrict the ability
849 // of an attacker leverage this capability by restricting false start
850 // to the same protocol we previously saw for the server, after the
851 // first successful connection to the server.
853 Telemetry::Accumulate(Telemetry::SSL_REASONS_FOR_NOT_FALSE_STARTING,
854 reasonsForNotFalseStarting);
856 if (reasonsForNotFalseStarting == 0) {
857 *canFalseStart = PR_TRUE;
858 infoObject->SetFalseStarted();
859 infoObject->NoteTimeUntilReady();
860 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
861 ("CanFalseStartCallback [%p] ok\n", fd));
864 return SECSuccess;
867 static void AccumulateNonECCKeySize(Telemetry::HistogramID probe,
868 uint32_t bits) {
869 unsigned int value = bits < 512 ? 1
870 : bits == 512 ? 2
871 : bits < 768 ? 3
872 : bits == 768 ? 4
873 : bits < 1024 ? 5
874 : bits == 1024 ? 6
875 : bits < 1280 ? 7
876 : bits == 1280 ? 8
877 : bits < 1536 ? 9
878 : bits == 1536 ? 10
879 : bits < 2048 ? 11
880 : bits == 2048 ? 12
881 : bits < 3072 ? 13
882 : bits == 3072 ? 14
883 : bits < 4096 ? 15
884 : bits == 4096 ? 16
885 : bits < 8192 ? 17
886 : bits == 8192 ? 18
887 : bits < 16384 ? 19
888 : bits == 16384 ? 20
889 : 0;
890 Telemetry::Accumulate(probe, value);
893 // XXX: This attempts to map a bit count to an ECC named curve identifier. In
894 // the vast majority of situations, we only have the Suite B curves available.
895 // In that case, this mapping works fine. If we were to have more curves
896 // available, the mapping would be ambiguous since there could be multiple
897 // named curves for a given size (e.g. secp256k1 vs. secp256r1). We punt on
898 // that for now. See also NSS bug 323674.
899 static void AccumulateECCCurve(Telemetry::HistogramID probe, uint32_t bits) {
900 unsigned int value = bits == 255 ? 29 // Curve25519
901 : bits == 256 ? 23 // P-256
902 : bits == 384 ? 24 // P-384
903 : bits == 521 ? 25 // P-521
904 : 0; // Unknown
905 Telemetry::Accumulate(probe, value);
908 static void AccumulateCipherSuite(const SSLChannelInfo& channelInfo) {
909 uint32_t value;
910 // Note: this list must include every cipher suite it is possible to enable
911 // in nsNSSComponent.cpp (see sCipherPrefs and sDeprecatedTLS1CipherPrefs).
912 switch (channelInfo.cipherSuite) {
913 case TLS_RSA_WITH_3DES_EDE_CBC_SHA: // 0x000A
914 value = 1;
915 break;
916 case TLS_RSA_WITH_AES_128_CBC_SHA: // 0x002F
917 value = 2;
918 break;
919 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: // 0x0033
920 value = 3;
921 break;
922 case TLS_RSA_WITH_AES_256_CBC_SHA: // 0x0035
923 value = 4;
924 break;
925 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: // 0x0039
926 value = 5;
927 break;
928 case TLS_RSA_WITH_AES_128_GCM_SHA256: // 0x009C
929 value = 6;
930 break;
931 case TLS_RSA_WITH_AES_256_GCM_SHA384: // 0x009D
932 value = 7;
933 break;
934 case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: // 0xC009
935 value = 8;
936 break;
937 case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: // 0xC00A
938 value = 9;
939 break;
940 case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: // 0xC013
941 value = 10;
942 break;
943 case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: // 0xC014
944 value = 11;
945 break;
946 case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: // 0xC02B
947 value = 12;
948 break;
949 case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: // 0xC02C
950 value = 13;
951 break;
952 case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: // 0xC02F
953 value = 14;
954 break;
955 case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: // 0xC030
956 value = 15;
957 break;
958 case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: // 0xCCA8
959 value = 16;
960 break;
961 case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: // 0xCCA9
962 value = 17;
963 break;
965 // TLS 1.3 cipher suites
966 case TLS_AES_128_GCM_SHA256: // 0x1301
967 value = 18;
968 break;
969 case TLS_AES_256_GCM_SHA384: // 0x1302
970 value = 19;
971 break;
972 case TLS_CHACHA20_POLY1305_SHA256: // 0x1303
973 value = 20;
974 break;
976 // unknown
977 default:
978 value = 0;
979 break;
981 MOZ_ASSERT(value != 0);
982 Telemetry::Accumulate(Telemetry::TLS_CIPHER_SUITE, value);
985 void HandshakeCallback(PRFileDesc* fd, void* client_data) {
986 // Do the bookkeeping that needs to be done after the
987 // server's ServerHello...ServerHelloDone have been processed, but that
988 // doesn't need the handshake to be completed.
989 PreliminaryHandshakeDone(fd);
991 NSSSocketControl* infoObject = (NSSSocketControl*)fd->higher->secret;
993 SSLVersionRange versions(infoObject->GetTLSVersionRange());
994 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
995 ("[%p] HandshakeCallback: succeeded using TLS version range "
996 "(0x%04x,0x%04x)\n",
997 fd, static_cast<unsigned int>(versions.min),
998 static_cast<unsigned int>(versions.max)));
999 // If the handshake completed, then we know the site is TLS tolerant
1000 infoObject->RememberTLSTolerant();
1002 SSLChannelInfo channelInfo;
1003 SECStatus rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
1004 MOZ_ASSERT(rv == SECSuccess);
1005 if (rv != SECSuccess) {
1006 return;
1008 AccumulateCipherSuite(channelInfo);
1010 // Get the protocol version for telemetry
1011 // 1=tls1, 2=tls1.1, 3=tls1.2, 4=tls1.3
1012 unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
1013 MOZ_ASSERT(versionEnum > 0);
1014 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
1016 SSLCipherSuiteInfo cipherInfo;
1017 rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
1018 sizeof cipherInfo);
1019 MOZ_ASSERT(rv == SECSuccess);
1020 if (rv != SECSuccess) {
1021 return;
1023 // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4, ecdh_hybrid=8
1024 Telemetry::Accumulate(infoObject->IsFullHandshake()
1025 ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
1026 : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
1027 channelInfo.keaType);
1029 if (infoObject->IsFullHandshake()) {
1030 switch (channelInfo.keaType) {
1031 case ssl_kea_rsa:
1032 AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
1033 channelInfo.keaKeyBits);
1034 break;
1035 case ssl_kea_dh:
1036 AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL,
1037 channelInfo.keaKeyBits);
1038 break;
1039 case ssl_kea_ecdh:
1040 AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL,
1041 channelInfo.keaKeyBits);
1042 break;
1043 case ssl_kea_ecdh_hybrid:
1044 break;
1045 default:
1046 MOZ_CRASH("impossible KEA");
1047 break;
1050 Telemetry::Accumulate(Telemetry::SSL_AUTH_ALGORITHM_FULL,
1051 channelInfo.authType);
1053 // RSA key exchange doesn't use a signature for auth.
1054 if (channelInfo.keaType != ssl_kea_rsa) {
1055 switch (channelInfo.authType) {
1056 case ssl_auth_rsa:
1057 case ssl_auth_rsa_sign:
1058 AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
1059 channelInfo.authKeyBits);
1060 break;
1061 case ssl_auth_ecdsa:
1062 AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL,
1063 channelInfo.authKeyBits);
1064 break;
1065 default:
1066 MOZ_CRASH("impossible auth algorithm");
1067 break;
1072 PRBool siteSupportsSafeRenego;
1073 if (channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_3) {
1074 rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
1075 &siteSupportsSafeRenego);
1076 MOZ_ASSERT(rv == SECSuccess);
1077 if (rv != SECSuccess) {
1078 siteSupportsSafeRenego = false;
1080 } else {
1081 // TLS 1.3 dropped support for renegotiation.
1082 siteSupportsSafeRenego = true;
1084 bool renegotiationUnsafe =
1085 !siteSupportsSafeRenego &&
1086 StaticPrefs::security_ssl_treat_unsafe_negotiation_as_broken();
1088 bool deprecatedTlsVer =
1089 (channelInfo.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_2);
1091 uint32_t state;
1092 if (renegotiationUnsafe || deprecatedTlsVer) {
1093 state = nsIWebProgressListener::STATE_IS_BROKEN;
1094 } else {
1095 state = nsIWebProgressListener::STATE_IS_SECURE;
1096 SSLVersionRange defVersion;
1097 rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion);
1098 if (rv == SECSuccess && versions.max >= defVersion.max) {
1099 // we know this site no longer requires a version fallback
1100 infoObject->RemoveInsecureTLSFallback();
1104 if (infoObject->HasServerCert()) {
1105 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
1106 ("HandshakeCallback KEEPING existing cert\n"));
1107 } else {
1108 infoObject->RebuildCertificateInfoFromSSLTokenCache();
1111 // Check if the user has added an override for a certificate error.
1112 if (infoObject->HasUserOverriddenCertificateError()) {
1113 state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
1116 infoObject->SetSecurityState(state);
1118 // XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
1119 // we should set a flag on the channel that higher (UI) level code can check
1120 // to log the warning. In particular, these warnings should go to the web
1121 // console instead of to the error console. Also, the warning is not
1122 // localized.
1123 if (!siteSupportsSafeRenego) {
1124 NS_ConvertASCIItoUTF16 msg(infoObject->GetHostName());
1125 msg.AppendLiteral(" : server does not support RFC 5746, see CVE-2009-3555");
1127 nsContentUtils::LogSimpleConsoleError(
1128 msg, "SSL"_ns, infoObject->GetOriginAttributes().IsPrivateBrowsing(),
1129 true /* from chrome context */);
1132 infoObject->NoteTimeUntilReady();
1133 infoObject->SetHandshakeCompleted();
1136 void SecretCallback(PRFileDesc* fd, PRUint16 epoch, SSLSecretDirection dir,
1137 PK11SymKey* secret, void* arg) {
1138 // arg must be set to an NSSSocketControl* in SSL_SecretCallback
1139 MOZ_ASSERT(arg);
1140 NSSSocketControl* infoObject = (NSSSocketControl*)arg;
1141 if (epoch == 2 && dir == ssl_secret_read) {
1142 // |secret| is the server_handshake_traffic_secret. Set a flag to indicate
1143 // that the Server Hello has been processed successfully. We use this when
1144 // deciding whether to retry a connection in which an mlkem768x25519 share
1145 // was sent.
1146 infoObject->SetHasTls13HandshakeSecrets();