Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / security / manager / ssl / NSSSocketControl.cpp
blob27ba9d1039694525b5e510badeeda8184b368f72
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 "NSSSocketControl.h"
9 #include "ssl.h"
10 #include "sslexp.h"
11 #include "nsISocketProvider.h"
12 #include "secerr.h"
13 #include "mozilla/Base64.h"
14 #include "mozilla/dom/Promise.h"
15 #include "nsNSSCallbacks.h"
16 #include "nsProxyRelease.h"
18 using namespace mozilla;
19 using namespace mozilla::psm;
21 extern LazyLogModule gPIPNSSLog;
23 NSSSocketControl::NSSSocketControl(
24 const nsCString& aHostName, int32_t aPort,
25 already_AddRefed<nsSSLIOLayerHelpers> aSSLIOLayerHelpers,
26 uint32_t providerFlags, uint32_t providerTlsFlags)
27 : CommonSocketControl(aHostName, aPort, providerFlags),
28 mFd(nullptr),
29 mCertVerificationState(BeforeCertVerification),
30 mSSLIOLayerHelpers(aSSLIOLayerHelpers),
31 mForSTARTTLS(false),
32 mTLSVersionRange{0, 0},
33 mHandshakePending(true),
34 mPreliminaryHandshakeDone(false),
35 mEarlyDataAccepted(false),
36 mDenyClientCert(false),
37 mFalseStartCallbackCalled(false),
38 mFalseStarted(false),
39 mIsFullHandshake(false),
40 mNotedTimeUntilReady(false),
41 mEchExtensionStatus(EchExtensionStatus::kNotPresent),
42 mSentMlkemShare(false),
43 mHasTls13HandshakeSecrets(false),
44 mIsShortWritePending(false),
45 mShortWritePendingByte(0),
46 mShortWriteOriginalAmount(-1),
47 mKEAUsed(nsITLSSocketControl::KEY_EXCHANGE_UNKNOWN),
48 mKEAKeyBits(0),
49 mMACAlgorithmUsed(nsITLSSocketControl::SSL_MAC_UNKNOWN),
50 mProviderTlsFlags(providerTlsFlags),
51 mSocketCreationTimestamp(TimeStamp::Now()),
52 mPlaintextBytesRead(0),
53 mClaimed(!(providerFlags & nsISocketProvider::IS_SPECULATIVE_CONNECTION)),
54 mPendingSelectClientAuthCertificate(nullptr),
55 mBrowserId(0) {}
57 NS_IMETHODIMP
58 NSSSocketControl::GetKEAUsed(int16_t* aKea) {
59 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
60 *aKea = mKEAUsed;
61 return NS_OK;
64 NS_IMETHODIMP
65 NSSSocketControl::GetKEAKeyBits(uint32_t* aKeyBits) {
66 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
67 *aKeyBits = mKEAKeyBits;
68 return NS_OK;
71 NS_IMETHODIMP
72 NSSSocketControl::GetSSLVersionOffered(int16_t* aSSLVersionOffered) {
73 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
74 *aSSLVersionOffered = mTLSVersionRange.max;
75 return NS_OK;
78 NS_IMETHODIMP
79 NSSSocketControl::GetMACAlgorithmUsed(int16_t* aMac) {
80 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
81 *aMac = mMACAlgorithmUsed;
82 return NS_OK;
85 void NSSSocketControl::NoteTimeUntilReady() {
86 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
87 if (mNotedTimeUntilReady) {
88 return;
90 mNotedTimeUntilReady = true;
92 auto timestampNow = TimeStamp::Now();
93 if (!(mProviderFlags & nsISocketProvider::IS_RETRY)) {
94 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY_FIRST_TRY,
95 mSocketCreationTimestamp, timestampNow);
98 if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) {
99 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY_CONSERVATIVE,
100 mSocketCreationTimestamp, timestampNow);
103 switch (GetEchExtensionStatus()) {
104 case EchExtensionStatus::kGREASE:
105 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY_ECH_GREASE,
106 mSocketCreationTimestamp, timestampNow);
107 break;
108 case EchExtensionStatus::kReal:
109 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY_ECH,
110 mSocketCreationTimestamp, timestampNow);
111 break;
112 default:
113 break;
115 // This will include TCP and proxy tunnel wait time
116 Telemetry::AccumulateTimeDelta(Telemetry::SSL_TIME_UNTIL_READY,
117 mSocketCreationTimestamp, timestampNow);
119 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
120 ("[%p] NSSSocketControl::NoteTimeUntilReady\n", mFd));
123 void NSSSocketControl::SetHandshakeCompleted() {
124 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
125 if (!mHandshakeCompleted) {
126 enum HandshakeType {
127 Resumption = 1,
128 FalseStarted = 2,
129 ChoseNotToFalseStart = 3,
130 NotAllowedToFalseStart = 4,
133 HandshakeType handshakeType = !IsFullHandshake() ? Resumption
134 : mFalseStarted ? FalseStarted
135 : mFalseStartCallbackCalled
136 ? ChoseNotToFalseStart
137 : NotAllowedToFalseStart;
138 // This will include TCP and proxy tunnel wait time
139 if (mKeaGroupName.isSome()) {
140 Telemetry::AccumulateTimeDelta(
141 Telemetry::SSL_TIME_UNTIL_HANDSHAKE_FINISHED_KEYED_BY_KA,
142 *mKeaGroupName, mSocketCreationTimestamp, TimeStamp::Now());
145 // If the handshake is completed for the first time from just 1 callback
146 // that means that TLS session resumption must have been used.
147 Telemetry::Accumulate(Telemetry::SSL_RESUMED_SESSION,
148 handshakeType == Resumption);
149 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_TYPE, handshakeType);
152 // Remove the plaintext layer as it is not needed anymore.
153 // The plaintext layer is not always present - so it's not a fatal error if it
154 // cannot be removed.
155 // Note that PR_PopIOLayer may modify its stack, so a pointer returned by
156 // PR_GetIdentitiesLayer may not point to what we think it points to after
157 // calling PR_PopIOLayer. We must operate on the pointer returned by
158 // PR_PopIOLayer.
159 if (PR_GetIdentitiesLayer(mFd,
160 nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) {
161 PRFileDesc* poppedPlaintext =
162 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
163 poppedPlaintext->dtor(poppedPlaintext);
166 mHandshakeCompleted = true;
168 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
169 ("[%p] NSSSocketControl::SetHandshakeCompleted\n", (void*)mFd));
171 mIsFullHandshake = false; // reset for next handshake on this connection
173 if (mTlsHandshakeCallback) {
174 auto callback = std::move(mTlsHandshakeCallback);
175 Unused << callback->HandshakeDone();
179 void NSSSocketControl::SetNegotiatedNPN(const char* value, uint32_t length) {
180 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
181 if (!value) {
182 mNegotiatedNPN.Truncate();
183 } else {
184 mNegotiatedNPN.Assign(value, length);
186 mNPNCompleted = true;
189 #define MAX_ALPN_LENGTH 255
191 NS_IMETHODIMP
192 NSSSocketControl::GetAlpnEarlySelection(nsACString& aAlpnSelected) {
193 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
194 aAlpnSelected.Truncate();
196 SSLPreliminaryChannelInfo info;
197 SECStatus rv = SSL_GetPreliminaryChannelInfo(mFd, &info, sizeof(info));
198 if (rv != SECSuccess || !info.canSendEarlyData) {
199 return NS_ERROR_NOT_AVAILABLE;
202 SSLNextProtoState alpnState;
203 unsigned char chosenAlpn[MAX_ALPN_LENGTH];
204 unsigned int chosenAlpnLen;
205 rv = SSL_GetNextProto(mFd, &alpnState, chosenAlpn, &chosenAlpnLen,
206 AssertedCast<unsigned int>(std::size(chosenAlpn)));
208 if (rv != SECSuccess) {
209 return NS_ERROR_NOT_AVAILABLE;
212 if (alpnState == SSL_NEXT_PROTO_EARLY_VALUE) {
213 aAlpnSelected.Assign(BitwiseCast<char*, unsigned char*>(chosenAlpn),
214 chosenAlpnLen);
217 return NS_OK;
220 NS_IMETHODIMP
221 NSSSocketControl::GetEarlyDataAccepted(bool* aAccepted) {
222 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
223 *aAccepted = mEarlyDataAccepted;
224 return NS_OK;
227 void NSSSocketControl::SetEarlyDataAccepted(bool aAccepted) {
228 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
229 mEarlyDataAccepted = aAccepted;
232 bool NSSSocketControl::GetDenyClientCert() {
233 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
234 return mDenyClientCert;
237 void NSSSocketControl::SetDenyClientCert(bool aDenyClientCert) {
238 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
239 mDenyClientCert = aDenyClientCert;
242 NS_IMETHODIMP
243 NSSSocketControl::DriveHandshake() {
244 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
245 if (!mFd) {
246 return NS_ERROR_FAILURE;
248 if (IsCanceled()) {
249 PRErrorCode errorCode = GetErrorCode();
250 MOZ_DIAGNOSTIC_ASSERT(errorCode, "handshake cancelled without error code");
251 return GetXPCOMFromNSSError(errorCode);
254 SECStatus rv = SSL_ForceHandshake(mFd);
256 if (rv != SECSuccess) {
257 PRErrorCode errorCode = PR_GetError();
258 MOZ_ASSERT(errorCode, "handshake failed without error code");
259 // There is a bug in NSS. Sometimes SSL_ForceHandshake will return
260 // SECFailure without setting an error code. In these cases, cancel
261 // the connection with SEC_ERROR_LIBRARY_FAILURE.
262 if (!errorCode) {
263 errorCode = SEC_ERROR_LIBRARY_FAILURE;
265 if (errorCode == PR_WOULD_BLOCK_ERROR) {
266 return NS_BASE_STREAM_WOULD_BLOCK;
269 SetCanceled(errorCode);
270 return GetXPCOMFromNSSError(errorCode);
272 return NS_OK;
275 bool NSSSocketControl::GetForSTARTTLS() {
276 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
277 return mForSTARTTLS;
280 void NSSSocketControl::SetForSTARTTLS(bool aForSTARTTLS) {
281 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
282 mForSTARTTLS = aForSTARTTLS;
285 NS_IMETHODIMP
286 NSSSocketControl::ProxyStartSSL() {
287 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
288 return ActivateSSL();
291 NS_IMETHODIMP
292 NSSSocketControl::StartTLS() {
293 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
294 return ActivateSSL();
297 NS_IMETHODIMP
298 NSSSocketControl::AsyncStartTLS(JSContext* aCx,
299 mozilla::dom::Promise** aPromise) {
300 MOZ_RELEASE_ASSERT(NS_IsMainThread());
301 NS_ENSURE_ARG_POINTER(aCx);
302 NS_ENSURE_ARG_POINTER(aPromise);
304 nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
305 if (!globalObject) {
306 return NS_ERROR_UNEXPECTED;
309 ErrorResult result;
310 RefPtr<mozilla::dom::Promise> promise =
311 mozilla::dom::Promise::Create(globalObject, result);
312 if (result.Failed()) {
313 return result.StealNSResult();
316 nsCOMPtr<nsIEventTarget> target(
317 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID));
318 if (!target) {
319 return NS_ERROR_UNEXPECTED;
322 auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
323 "AsyncStartTLS promise", promise);
325 nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
326 "AsyncStartTLS::StartTLS",
327 [promiseHolder = std::move(promiseHolder), self = RefPtr{this}]() {
328 nsresult rv = self->StartTLS();
329 NS_DispatchToMainThread(NS_NewRunnableFunction(
330 "AsyncStartTLS::Resolve", [rv, promiseHolder]() {
331 dom::Promise* promise = promiseHolder.get()->get();
332 if (NS_FAILED(rv)) {
333 promise->MaybeReject(rv);
334 } else {
335 promise->MaybeResolveWithUndefined();
337 }));
338 }));
340 nsresult rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
341 if (NS_FAILED(rv)) {
342 return rv;
345 promise.forget(aPromise);
346 return NS_OK;
349 NS_IMETHODIMP
350 NSSSocketControl::SetNPNList(nsTArray<nsCString>& protocolArray) {
351 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
352 if (!mFd) return NS_ERROR_FAILURE;
354 // the npn list is a concatenated list of 8 bit byte strings.
355 nsCString npnList;
357 for (uint32_t index = 0; index < protocolArray.Length(); ++index) {
358 if (protocolArray[index].IsEmpty() || protocolArray[index].Length() > 255)
359 return NS_ERROR_ILLEGAL_VALUE;
361 npnList.Append(protocolArray[index].Length());
362 npnList.Append(protocolArray[index]);
365 if (SSL_SetNextProtoNego(
366 mFd, BitwiseCast<const unsigned char*, const char*>(npnList.get()),
367 npnList.Length()) != SECSuccess)
368 return NS_ERROR_FAILURE;
370 return NS_OK;
373 nsresult NSSSocketControl::ActivateSSL() {
374 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
375 if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
376 return NS_ERROR_FAILURE;
377 if (SECSuccess != SSL_ResetHandshake(mFd, false)) return NS_ERROR_FAILURE;
379 mHandshakePending = true;
381 return SetResumptionTokenFromExternalCache(mFd);
384 nsresult NSSSocketControl::GetFileDescPtr(PRFileDesc** aFilePtr) {
385 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
386 *aFilePtr = mFd;
387 return NS_OK;
390 nsresult NSSSocketControl::SetFileDescPtr(PRFileDesc* aFilePtr) {
391 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
392 mFd = aFilePtr;
393 return NS_OK;
396 void NSSSocketControl::SetCertVerificationWaiting() {
397 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
398 // mCertVerificationState may be BeforeCertVerification for the first
399 // handshake on the connection, or AfterCertVerification for subsequent
400 // renegotiation handshakes.
401 MOZ_ASSERT(mCertVerificationState != WaitingForCertVerification,
402 "Invalid state transition to WaitingForCertVerification");
403 mCertVerificationState = WaitingForCertVerification;
406 // Be careful that SetCertVerificationResult does NOT get called while we are
407 // processing a SSL callback function, because SSL_AuthCertificateComplete will
408 // attempt to acquire locks that are already held by libssl when it calls
409 // callbacks.
410 void NSSSocketControl::SetCertVerificationResult(PRErrorCode errorCode) {
411 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
412 SetUsedPrivateDNS(GetProviderFlags() & nsISocketProvider::USED_PRIVATE_DNS);
413 MOZ_ASSERT(mCertVerificationState == WaitingForCertVerification,
414 "Invalid state transition to AfterCertVerification");
416 if (mFd) {
417 SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
418 // Only replace errorCode if there was originally no error.
419 // SSL_AuthCertificateComplete will return SECFailure with the error code
420 // set to PR_WOULD_BLOCK_ERROR if there is a pending event to select a
421 // client authentication certificate. This is not an error.
422 if (rv != SECSuccess && PR_GetError() != PR_WOULD_BLOCK_ERROR &&
423 errorCode == 0) {
424 errorCode = PR_GetError();
425 if (errorCode == 0) {
426 NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
427 errorCode = PR_INVALID_STATE_ERROR;
432 if (errorCode) {
433 mFailedVerification = true;
434 SetCanceled(errorCode);
437 if (mPlaintextBytesRead && !errorCode) {
438 Telemetry::Accumulate(Telemetry::SSL_BYTES_BEFORE_CERT_CALLBACK,
439 AssertedCast<uint32_t>(mPlaintextBytesRead));
442 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
443 ("[%p] SetCertVerificationResult to AfterCertVerification, "
444 "mTlsHandshakeCallback=%p",
445 (void*)mFd, mTlsHandshakeCallback.get()));
447 mCertVerificationState = AfterCertVerification;
448 if (mTlsHandshakeCallback) {
449 Unused << mTlsHandshakeCallback->CertVerificationDone();
453 void NSSSocketControl::ClientAuthCertificateSelected(
454 nsTArray<uint8_t>& certBytes, nsTArray<nsTArray<uint8_t>>& certChainBytes) {
455 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
456 // If mFd is nullptr, the connection has been closed already, so we don't
457 // need to do anything here.
458 if (!mFd) {
459 return;
461 SECItem certItem = {
462 siBuffer,
463 const_cast<uint8_t*>(certBytes.Elements()),
464 static_cast<unsigned int>(certBytes.Length()),
466 UniqueCERTCertificate cert(CERT_NewTempCertificate(
467 CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
468 UniqueSECKEYPrivateKey key;
469 if (cert) {
470 key.reset(PK11_FindKeyByAnyCert(cert.get(), nullptr));
471 mClientCertChain.reset(CERT_NewCertList());
472 if (key && mClientCertChain) {
473 for (const auto& certBytes : certChainBytes) {
474 SECItem certItem = {
475 siBuffer,
476 const_cast<uint8_t*>(certBytes.Elements()),
477 static_cast<unsigned int>(certBytes.Length()),
479 UniqueCERTCertificate cert(CERT_NewTempCertificate(
480 CERT_GetDefaultCertDB(), &certItem, nullptr, false, true));
481 if (cert) {
482 if (CERT_AddCertToListTail(mClientCertChain.get(), cert.get()) ==
483 SECSuccess) {
484 Unused << cert.release();
491 bool sendingClientAuthCert = cert && key;
492 if (sendingClientAuthCert) {
493 mSentClientCert = true;
494 glean::security::client_auth_cert_usage.Get("sent"_ns).Add(1);
497 Unused << SSL_ClientCertCallbackComplete(
498 mFd, sendingClientAuthCert ? SECSuccess : SECFailure,
499 sendingClientAuthCert ? key.release() : nullptr,
500 sendingClientAuthCert ? cert.release() : nullptr);
502 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
503 ("[%p] ClientAuthCertificateSelected mTlsHandshakeCallback=%p",
504 (void*)mFd, mTlsHandshakeCallback.get()));
505 if (mTlsHandshakeCallback) {
506 Unused << mTlsHandshakeCallback->ClientAuthCertificateSelected();
510 NS_IMETHODIMP
511 NSSSocketControl::DisableEarlyData() {
512 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
513 if (!mFd) {
514 return NS_OK;
516 if (IsCanceled()) {
517 return NS_OK;
520 if (SSL_OptionSet(mFd, SSL_ENABLE_0RTT_DATA, false) != SECSuccess) {
521 return NS_ERROR_FAILURE;
523 return NS_OK;
526 NS_IMETHODIMP
527 NSSSocketControl::SetHandshakeCallbackListener(
528 nsITlsHandshakeCallbackListener* callback) {
529 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
530 mTlsHandshakeCallback = callback;
531 return NS_OK;
534 PRStatus NSSSocketControl::CloseSocketAndDestroy() {
535 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
537 mPendingSelectClientAuthCertificate = nullptr;
539 PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
540 MOZ_ASSERT(
541 popped && popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
542 "SSL Layer not on top of stack");
544 // The plaintext layer is not always present - so it's not a fatal error if it
545 // cannot be removed.
546 // Note that PR_PopIOLayer may modify its stack, so a pointer returned by
547 // PR_GetIdentitiesLayer may not point to what we think it points to after
548 // calling PR_PopIOLayer. We must operate on the pointer returned by
549 // PR_PopIOLayer.
550 if (PR_GetIdentitiesLayer(mFd,
551 nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) {
552 PRFileDesc* poppedPlaintext =
553 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity);
554 poppedPlaintext->dtor(poppedPlaintext);
557 // We need to clear the callback to make sure the ssl layer cannot call the
558 // callback after mFD is nulled.
559 SSL_SetResumptionTokenCallback(mFd, nullptr, nullptr);
561 PRStatus status = mFd->methods->close(mFd);
563 // the NSSSocketControl instance can out-live the connection, so we need some
564 // indication that the connection has been closed. mFd == nullptr is that
565 // indication. This is needed, for example, when the connection is closed
566 // before we have finished validating the server's certificate.
567 mFd = nullptr;
569 if (status != PR_SUCCESS) return status;
571 popped->identity = PR_INVALID_IO_LAYER;
572 popped->dtor(popped);
574 return PR_SUCCESS;
577 NS_IMETHODIMP
578 NSSSocketControl::GetEsniTxt(nsACString& aEsniTxt) {
579 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
580 aEsniTxt = mEsniTxt;
581 return NS_OK;
584 NS_IMETHODIMP
585 NSSSocketControl::SetEsniTxt(const nsACString& aEsniTxt) {
586 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
587 mEsniTxt = aEsniTxt;
589 if (mEsniTxt.Length()) {
590 nsAutoCString esniBin;
591 if (NS_OK != Base64Decode(mEsniTxt, esniBin)) {
592 MOZ_LOG(gPIPNSSLog, LogLevel::Error,
593 ("[%p] Invalid ESNIKeys record. Couldn't base64 decode\n",
594 (void*)mFd));
595 return NS_OK;
598 if (SECSuccess !=
599 SSL_EnableESNI(mFd, reinterpret_cast<const PRUint8*>(esniBin.get()),
600 esniBin.Length(), nullptr)) {
601 MOZ_LOG(gPIPNSSLog, LogLevel::Error,
602 ("[%p] Invalid ESNIKeys record %s\n", (void*)mFd,
603 PR_ErrorToName(PR_GetError())));
604 return NS_OK;
608 return NS_OK;
611 NS_IMETHODIMP
612 NSSSocketControl::GetEchConfig(nsACString& aEchConfig) {
613 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
614 aEchConfig = mEchConfig;
615 return NS_OK;
618 NS_IMETHODIMP
619 NSSSocketControl::SetEchConfig(const nsACString& aEchConfig) {
620 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
621 mEchConfig = aEchConfig;
623 if (mEchConfig.Length()) {
624 if (SECSuccess !=
625 SSL_SetClientEchConfigs(
626 mFd, reinterpret_cast<const PRUint8*>(aEchConfig.BeginReading()),
627 aEchConfig.Length())) {
628 MOZ_LOG(gPIPNSSLog, LogLevel::Error,
629 ("[%p] Invalid EchConfig record %s\n", (void*)mFd,
630 PR_ErrorToName(PR_GetError())));
631 return NS_OK;
633 UpdateEchExtensionStatus(EchExtensionStatus::kReal);
635 return NS_OK;
638 NS_IMETHODIMP
639 NSSSocketControl::GetRetryEchConfig(nsACString& aEchConfig) {
640 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
641 if (!mFd) {
642 return NS_ERROR_FAILURE;
645 ScopedAutoSECItem retryConfigItem;
646 SECStatus rv = SSL_GetEchRetryConfigs(mFd, &retryConfigItem);
647 if (rv != SECSuccess) {
648 return NS_ERROR_FAILURE;
650 aEchConfig = nsCString(reinterpret_cast<const char*>(retryConfigItem.data),
651 retryConfigItem.len);
652 return NS_OK;
655 NS_IMETHODIMP
656 NSSSocketControl::GetPeerId(nsACString& aResult) {
657 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
658 if (!mPeerId.IsEmpty()) {
659 aResult.Assign(mPeerId);
660 return NS_OK;
663 if (mProviderFlags &
664 nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080
665 mPeerId.AppendLiteral("anon:");
667 if (mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE) {
668 mPeerId.AppendLiteral("private:");
670 if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) {
671 mPeerId.AppendLiteral("beConservative:");
674 mPeerId.AppendPrintf("tlsflags0x%08x:", mProviderTlsFlags);
676 mPeerId.Append(mHostName);
677 mPeerId.Append(':');
678 mPeerId.AppendInt(GetPort());
679 nsAutoCString suffix;
680 mOriginAttributes.CreateSuffix(suffix);
681 mPeerId.Append(suffix);
683 aResult.Assign(mPeerId);
684 return NS_OK;
687 nsresult NSSSocketControl::SetResumptionTokenFromExternalCache(PRFileDesc* fd) {
688 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
689 if (!fd) {
690 return NS_ERROR_INVALID_ARG;
693 // If SSL_NO_CACHE option was set, we must not use the cache
694 PRIntn val;
695 if (SSL_OptionGet(fd, SSL_NO_CACHE, &val) != SECSuccess) {
696 return NS_ERROR_FAILURE;
699 if (val != 0) {
700 return NS_OK;
703 nsTArray<uint8_t> token;
704 nsAutoCString peerId;
705 nsresult rv = GetPeerId(peerId);
706 if (NS_FAILED(rv)) {
707 return rv;
710 uint64_t tokenId = 0;
711 mozilla::net::SessionCacheInfo info;
712 rv = mozilla::net::SSLTokensCache::Get(peerId, token, info, &tokenId);
713 if (NS_FAILED(rv)) {
714 if (rv == NS_ERROR_NOT_AVAILABLE) {
715 // It's ok if we can't find the token.
716 return NS_OK;
719 return rv;
722 SECStatus srv = SSL_SetResumptionToken(fd, token.Elements(), token.Length());
723 if (srv == SECFailure) {
724 PRErrorCode error = PR_GetError();
725 mozilla::net::SSLTokensCache::Remove(peerId, tokenId);
726 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
727 ("Setting token failed with NSS error %d [id=%s]", error,
728 PromiseFlatCString(peerId).get()));
729 // We don't consider SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR as a hard error,
730 // since this error means this token is just expired or can't be decoded
731 // correctly.
732 if (error == SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR) {
733 return NS_OK;
736 return NS_ERROR_FAILURE;
739 SetSessionCacheInfo(std::move(info));
741 return NS_OK;
744 void NSSSocketControl::SetPreliminaryHandshakeInfo(
745 const SSLChannelInfo& channelInfo, const SSLCipherSuiteInfo& cipherInfo) {
746 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
747 mResumed = channelInfo.resumed;
748 mCipherSuite.emplace(channelInfo.cipherSuite);
749 mProtocolVersion.emplace(channelInfo.protocolVersion & 0xFF);
750 mKeaGroupName.emplace(getKeaGroupName(channelInfo.keaGroup));
751 mSignatureSchemeName.emplace(getSignatureName(channelInfo.signatureScheme));
752 mIsDelegatedCredential.emplace(channelInfo.peerDelegCred);
753 mIsAcceptedEch.emplace(channelInfo.echAccepted);
756 NS_IMETHODIMP NSSSocketControl::Claim() {
757 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
758 mClaimed = true;
759 return NS_OK;
762 NS_IMETHODIMP NSSSocketControl::SetBrowserId(uint64_t browserId) {
763 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
764 mBrowserId = browserId;
765 return NS_OK;
768 NS_IMETHODIMP NSSSocketControl::GetBrowserId(uint64_t* browserId) {
769 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD();
770 if (!browserId) {
771 return NS_ERROR_INVALID_ARG;
773 *browserId = mBrowserId;
774 return NS_OK;