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"
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
;
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;
70 class OCSPRequest final
: public nsIStreamLoaderObserver
, public nsIRunnable
{
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
81 nsresult
DispatchToMainThreadAndWait();
82 nsresult
GetResponse(/*out*/ Vector
<uint8_t>& response
);
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
;
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),
129 mAIALocation(aiaLocation
),
130 mOriginAttributes(originAttributes
),
131 mPOSTData(reinterpret_cast<const char*>(ocspRequest
), ocspRequestLength
),
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);
149 while (!mNotifiedDone
) {
153 // CERT_VALIDATION_HTTP_REQUEST_RESULT:
154 // 0: request timed out
155 // 1: request succeeded
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
);
171 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT
, 2);
172 mozilla::glean::ocsp_request_time::failure
.AccumulateRawDuration(
173 TimeStamp::Now() - mStartTime
);
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
;
192 if (!response
.append(mResponseBytes
.begin(), mResponseBytes
.length())) {
193 return NS_ERROR_OUT_OF_MEMORY
;
198 static constexpr auto OCSP_REQUEST_MIME_TYPE
= "application/ocsp-request"_ns
;
199 static constexpr auto OCSP_REQUEST_METHOD
= "POST"_ns
;
203 MOZ_ASSERT(NS_IsMainThread());
204 if (!NS_IsMainThread()) {
205 return NS_ERROR_FAILURE
;
208 MonitorAutoLock
lock(mMonitor
);
210 nsCOMPtr
<nsIIOService
> ios
= do_GetIOService();
212 return NotifyDone(NS_ERROR_FAILURE
, lock
);
215 nsCOMPtr
<nsIURI
> uri
;
216 nsresult rv
= NS_NewURI(getter_AddRefs(uri
), mAIALocation
);
218 return NotifyDone(NS_ERROR_MALFORMED_URI
, lock
);
220 nsAutoCString scheme
;
221 rv
= uri
->GetScheme(scheme
);
223 return NotifyDone(rv
, lock
);
225 if (!scheme
.LowerCaseEqualsLiteral("http")) {
226 return NotifyDone(NS_ERROR_MALFORMED_URI
, lock
);
230 // We should not send OCSP request if the PAC is still loading.
231 nsCOMPtr
<nsIProtocolProxyService
> pps
=
232 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID
, &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
));
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
281 if (mOriginAttributes
!= OriginAttributes()) {
282 OriginAttributes attrs
;
283 attrs
.mFirstPartyDomain
= mOriginAttributes
.mFirstPartyDomain
;
284 attrs
.mPrivateBrowsingId
= mOriginAttributes
.mPrivateBrowsingId
;
286 rv
= loadInfo
->SetOriginAttributes(attrs
);
288 return NotifyDone(rv
, lock
);
292 nsCOMPtr
<nsIInputStream
> uploadStream
;
293 rv
= NS_NewByteInputStream(getter_AddRefs(uploadStream
), mPOSTData
,
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);
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
310 nsCOMPtr
<nsIHttpChannelInternal
> internalChannel
= do_QueryInterface(channel
);
311 if (!internalChannel
) {
312 return NotifyDone(rv
, lock
);
314 rv
= internalChannel
->SetAllowSpdy(false);
316 return NotifyDone(rv
, lock
);
318 rv
= internalChannel
->SetAllowHttp3(false);
320 return NotifyDone(rv
, lock
);
322 rv
= internalChannel
->SetIsOCSP(true);
324 return NotifyDone(rv
, lock
);
326 nsCOMPtr
<nsIHttpChannel
> hchan
= do_QueryInterface(channel
);
328 return NotifyDone(NS_ERROR_FAILURE
, lock
);
330 rv
= hchan
->SetAllowSTS(false);
332 return NotifyDone(rv
, lock
);
334 rv
= hchan
->SetRequestMethod(OCSP_REQUEST_METHOD
);
336 return NotifyDone(rv
, lock
);
339 rv
= NS_NewStreamLoader(getter_AddRefs(mLoader
), this);
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");
348 return NotifyDone(rv
, lock
);
350 rv
= hchan
->AsyncOpen(this->mLoader
);
352 return NotifyDone(rv
, lock
);
354 mStartTime
= TimeStamp::Now();
358 nsresult
OCSPRequest::NotifyDone(nsresult rv
, MonitorAutoLock
& lock
) {
359 MOZ_ASSERT(NS_IsMainThread());
360 if (!NS_IsMainThread()) {
361 return NS_ERROR_FAILURE
;
365 return mResponseResult
;
368 mResponseResult
= rv
;
370 Unused
<< mTimeoutTimer
->Cancel();
372 mNotifiedDone
= true;
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
));
391 return NotifyDone(rv
, lock
);
394 if (NS_FAILED(aStatus
)) {
395 return NotifyDone(aStatus
, lock
);
398 nsCOMPtr
<nsIHttpChannel
> hchan
= do_QueryInterface(req
);
400 return NotifyDone(NS_ERROR_FAILURE
, lock
);
403 bool requestSucceeded
;
404 rv
= hchan
->GetRequestSucceeded(&requestSucceeded
);
406 return NotifyDone(rv
, lock
);
408 if (!requestSucceeded
) {
409 return NotifyDone(NS_ERROR_FAILURE
, lock
);
413 rv
= hchan
->GetResponseStatus(&rcode
);
415 return NotifyDone(rv
, lock
);
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()) {
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
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
;
459 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
460 ("DoOCSPRequest to '%s'", aiaLocation
.get()));
462 nsCOMPtr
<nsIEventTarget
> sts
=
463 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID
);
466 return mozilla::pkix::Result::FATAL_ERROR_INVALID_STATE
;
469 nsresult rv
= sts
->IsOnCurrentThread(&onSTSThread
);
471 return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE
;
473 MOZ_ASSERT(!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();
482 return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE
;
484 rv
= request
->GetResponse(result
);
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
;
494 static char* ShowProtectedAuthPrompt(PK11SlotInfo
* slot
, nsIPrompt
* prompt
) {
495 MOZ_ASSERT(NS_IsMainThread());
498 if (!NS_IsMainThread() || !slot
|| !prompt
) {
502 // Dispatch a background task to (eventually) call C_Login. The call will
503 // block until the protected authentication succeeds or fails.
505 Atomic
<SECStatus
> result
;
507 NS_DispatchBackgroundTask(NS_NewRunnableFunction(__func__
, [&]() mutable {
508 result
= PK11_CheckUserPassword(slot
, 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())) {
532 rv
= prompt
->Alert(nullptr, NS_ConvertUTF8toUTF16(promptString
).get());
537 MOZ_ALWAYS_TRUE(SpinEventLoopUntil(
538 "ShowProtectedAuthPrompt"_ns
, [&]() { return static_cast<bool>(done
); }));
542 return ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED
));
544 return ToNewCString(nsDependentCString(PK11_PW_RETRY
));
550 class PK11PasswordPromptRunnable
: public SyncRunnableBase
{
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
;
560 static bool mRunning
;
563 nsIInterfaceRequestor
* mIR
;
566 bool PK11PasswordPromptRunnable::mRunning
= false;
568 void PK11PasswordPromptRunnable::RunOnTargetThread() {
569 MOZ_ASSERT(NS_IsMainThread());
570 if (!NS_IsMainThread()) {
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.
584 auto setRunningToFalseOnExit
= MakeScopeExit([&]() { mRunning
= false; });
587 nsCOMPtr
<nsIPrompt
> prompt
;
589 rv
= nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt
));
594 prompt
= do_GetInterface(mIR
);
595 MOZ_ASSERT(prompt
, "Interface requestor should implement nsIPrompt");
602 if (PK11_ProtectedAuthenticationPath(mSlot
)) {
603 mResult
= ShowProtectedAuthPrompt(mSlot
, prompt
);
607 nsAutoString promptString
;
608 if (PK11_IsInternal(mSlot
)) {
609 rv
= GetPIPNSSBundleString("CertPasswordPromptDefault", promptString
);
611 AutoTArray
<nsString
, 1> formatStrings
= {
612 NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot
))};
613 rv
= PIPBundleFormatStringFromName("CertPasswordPrompt", formatStrings
,
621 bool userClickedOK
= false;
622 rv
= prompt
->PromptPassword(nullptr, promptString
.get(),
623 getter_Copies(password
), &userClickedOK
);
624 if (NS_FAILED(rv
) || !userClickedOK
) {
628 mResult
= ToNewUTF8String(password
);
631 char* PK11PasswordPrompt(PK11SlotInfo
* slot
, PRBool
/*retry*/, void* arg
) {
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
) {
644 case ssl_grp_ec_secp256r1
:
645 groupName
= "P256"_ns
;
647 case ssl_grp_ec_secp384r1
:
648 groupName
= "P384"_ns
;
650 case ssl_grp_ec_secp521r1
:
651 groupName
= "P521"_ns
;
653 case ssl_grp_ec_curve25519
:
654 groupName
= "x25519"_ns
;
656 case ssl_grp_kem_xyber768d00
:
657 groupName
= "xyber768d00"_ns
;
659 case ssl_grp_kem_mlkem768x25519
:
660 groupName
= "mlkem768x25519"_ns
;
662 case ssl_grp_ffdhe_2048
:
663 groupName
= "FF 2048"_ns
;
665 case ssl_grp_ffdhe_3072
:
666 groupName
= "FF 3072"_ns
;
669 groupName
= "none"_ns
;
671 case ssl_grp_ffdhe_custom
:
672 groupName
= "custom"_ns
;
674 // All other groups are not enabled in Firefox. See namedGroups in
677 // This really shouldn't happen!
678 MOZ_ASSERT_UNREACHABLE("Invalid key exchange group.");
679 groupName
= "unknown group"_ns
;
684 nsCString
getSignatureName(uint32_t aSignatureScheme
) {
685 nsCString signatureName
;
686 switch (aSignatureScheme
) {
688 signatureName
= "none"_ns
;
690 case ssl_sig_rsa_pkcs1_sha1
:
691 signatureName
= "RSA-PKCS1-SHA1"_ns
;
693 case ssl_sig_rsa_pkcs1_sha256
:
694 signatureName
= "RSA-PKCS1-SHA256"_ns
;
696 case ssl_sig_rsa_pkcs1_sha384
:
697 signatureName
= "RSA-PKCS1-SHA384"_ns
;
699 case ssl_sig_rsa_pkcs1_sha512
:
700 signatureName
= "RSA-PKCS1-SHA512"_ns
;
702 case ssl_sig_ecdsa_secp256r1_sha256
:
703 signatureName
= "ECDSA-P256-SHA256"_ns
;
705 case ssl_sig_ecdsa_secp384r1_sha384
:
706 signatureName
= "ECDSA-P384-SHA384"_ns
;
708 case ssl_sig_ecdsa_secp521r1_sha512
:
709 signatureName
= "ECDSA-P521-SHA512"_ns
;
711 case ssl_sig_rsa_pss_sha256
:
712 signatureName
= "RSA-PSS-SHA256"_ns
;
714 case ssl_sig_rsa_pss_sha384
:
715 signatureName
= "RSA-PSS-SHA384"_ns
;
717 case ssl_sig_rsa_pss_sha512
:
718 signatureName
= "RSA-PSS-SHA512"_ns
;
720 case ssl_sig_ecdsa_sha1
:
721 signatureName
= "ECDSA-SHA1"_ns
;
723 case ssl_sig_rsa_pkcs1_sha1md5
:
724 signatureName
= "RSA-PKCS1-SHA1MD5"_ns
;
726 // All other groups are not enabled in Firefox. See sEnabledSignatureSchemes
727 // in nsNSSIOLayer.cpp.
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
) {
741 if (socketControl
->IsPreliminaryHandshakeDone()) {
745 SSLChannelInfo channelInfo
;
746 if (SSL_GetChannelInfo(fd
, &channelInfo
, sizeof(channelInfo
)) != SECSuccess
) {
749 SSLCipherSuiteInfo cipherInfo
;
750 if (SSL_GetCipherSuiteInfo(channelInfo
.cipherSuite
, &cipherInfo
,
751 sizeof(cipherInfo
)) != SECSuccess
) {
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];
766 if (SSL_GetNextProto(fd
, &state
, npnbuf
, &npnlen
,
767 AssertedCast
<unsigned int>(std::size(npnbuf
))) ==
769 if (state
== SSL_NEXT_PROTO_NEGOTIATED
||
770 state
== SSL_NEXT_PROTO_SELECTED
) {
771 socketControl
->SetNegotiatedNPN(
772 BitwiseCast
<char*, unsigned char*>(npnbuf
), npnlen
);
774 socketControl
->SetNegotiatedNPN(nullptr, 0);
776 mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE
, state
);
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
;
790 PR_SetError(PR_INVALID_STATE_ERROR
, 0);
794 infoObject
->SetFalseStartCallbackCalled();
796 PreliminaryHandshakeDone(fd
);
798 uint32_t reasonsForNotFalseStarting
= 0;
800 SSLChannelInfo channelInfo
;
801 if (SSL_GetChannelInfo(fd
, &channelInfo
, sizeof(channelInfo
)) != 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 - "
811 fd
, static_cast<int32_t>(channelInfo
.keaType
)));
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
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
));
867 static void AccumulateNonECCKeySize(Telemetry::HistogramID probe
,
869 unsigned int value
= bits
< 512 ? 1
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
905 Telemetry::Accumulate(probe
, value
);
908 static void AccumulateCipherSuite(const SSLChannelInfo
& channelInfo
) {
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
916 case TLS_RSA_WITH_AES_128_CBC_SHA
: // 0x002F
919 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA
: // 0x0033
922 case TLS_RSA_WITH_AES_256_CBC_SHA
: // 0x0035
925 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA
: // 0x0039
928 case TLS_RSA_WITH_AES_128_GCM_SHA256
: // 0x009C
931 case TLS_RSA_WITH_AES_256_GCM_SHA384
: // 0x009D
934 case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
: // 0xC009
937 case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
: // 0xC00A
940 case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
: // 0xC013
943 case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
: // 0xC014
946 case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
: // 0xC02B
949 case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
: // 0xC02C
952 case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
: // 0xC02F
955 case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
: // 0xC030
958 case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
: // 0xCCA8
961 case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
: // 0xCCA9
965 // TLS 1.3 cipher suites
966 case TLS_AES_128_GCM_SHA256
: // 0x1301
969 case TLS_AES_256_GCM_SHA384
: // 0x1302
972 case TLS_CHACHA20_POLY1305_SHA256
: // 0x1303
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 "
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
) {
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
,
1019 MOZ_ASSERT(rv
== SECSuccess
);
1020 if (rv
!= SECSuccess
) {
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
) {
1032 AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL
,
1033 channelInfo
.keaKeyBits
);
1036 AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL
,
1037 channelInfo
.keaKeyBits
);
1040 AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL
,
1041 channelInfo
.keaKeyBits
);
1043 case ssl_kea_ecdh_hybrid
:
1046 MOZ_CRASH("impossible KEA");
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
) {
1057 case ssl_auth_rsa_sign
:
1058 AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL
,
1059 channelInfo
.authKeyBits
);
1061 case ssl_auth_ecdsa
:
1062 AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL
,
1063 channelInfo
.authKeyBits
);
1066 MOZ_CRASH("impossible auth algorithm");
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;
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
);
1092 if (renegotiationUnsafe
|| deprecatedTlsVer
) {
1093 state
= nsIWebProgressListener::STATE_IS_BROKEN
;
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"));
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
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
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
1146 infoObject
->SetHasTls13HandshakeSecrets();