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 "nsNSSIOLayer.h"
13 #include "NSSCertDBTrustDomain.h"
14 #include "NSSErrorsService.h"
15 #include "NSSSocketControl.h"
16 #include "PSMRunnable.h"
17 #include "SSLServerCertVerification.h"
18 #include "ScopedNSSTypes.h"
19 #include "TLSClientAuthCertSelection.h"
21 #include "mozilla/Base64.h"
22 #include "mozilla/DebugOnly.h"
23 #include "mozilla/Logging.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/RandomNum.h"
26 #include "mozilla/ScopeExit.h"
27 #include "mozilla/StaticPrefs_security.h"
28 #include "mozilla/Telemetry.h"
29 #include "mozilla/glean/GleanMetrics.h"
30 #include "mozilla/net/SSLTokensCache.h"
31 #include "mozilla/net/SocketProcessChild.h"
32 #include "mozilla/psm/IPCClientCertsChild.h"
33 #include "mozilla/psm/PIPCClientCertsChild.h"
34 #include "mozpkix/pkixnss.h"
35 #include "mozpkix/pkixtypes.h"
36 #include "mozpkix/pkixutil.h"
38 #include "nsArrayUtils.h"
40 #include "nsCharSeparatedTokenizer.h"
41 #include "nsClientAuthRemember.h"
42 #include "nsContentUtils.h"
43 #include "nsISocketProvider.h"
44 #include "nsIWebProgressListener.h"
45 #include "nsNSSComponent.h"
46 #include "nsNSSHelper.h"
47 #include "nsPrintfCString.h"
48 #include "nsServiceManagerUtils.h"
58 #include "brotli/decode.h"
59 #include "zstd/zstd.h"
62 # include "mozilla/arm.h"
65 using namespace mozilla
;
66 using namespace mozilla::psm
;
67 using namespace mozilla::ipc
;
69 // #define DEBUG_SSL_VERBOSE //Enable this define to get minimal
70 // reports when doing SSL read/write
72 // #define DUMP_BUFFER //Enable this define along with
73 // DEBUG_SSL_VERBOSE to dump SSL
74 // read/write buffer to a log.
75 // Uses PR_LOG except on Mac where
76 // we always write out to our own
81 // The NSSSocketInfo tls flags are meant to be opaque to most calling
82 // applications but provide a mechanism for direct TLS manipulation when
83 // experimenting with new features in the scope of a single socket. They do not
84 // create a persistent ABI.
86 // Use of these flags creates a new 'sharedSSLState' so existing states for
87 // intolerance are not carried to sockets that use these flags (and intolerance
88 // they discover does not impact other normal sockets not using the flags.)
90 // Their current definitions are:
92 // bits 0-2 (mask 0x07) specify the max tls version
93 // 0 means no override 1->4 are 1.0, 1.1, 1.2, 1.3, 4->7 unused
94 // bits 3-5 (mask 0x38) specify the tls fallback limit
95 // 0 means no override, values 1->4 match prefs
96 // bit 6 (mask 0x40) was used to specify compat mode. Temporarily reserved.
99 kTLSProviderFlagMaxVersion10
= 0x01,
100 kTLSProviderFlagMaxVersion11
= 0x02,
101 kTLSProviderFlagMaxVersion12
= 0x03,
102 kTLSProviderFlagMaxVersion13
= 0x04,
105 static uint32_t getTLSProviderFlagMaxVersion(uint32_t flags
) {
106 return (flags
& 0x07);
109 static uint32_t getTLSProviderFlagFallbackLimit(uint32_t flags
) {
110 return (flags
& 0x38) >> 3;
113 void getSiteKey(const nsACString
& hostName
, uint16_t port
,
114 /*out*/ nsACString
& key
) {
116 key
.AppendLiteral(":");
120 } // unnamed namespace
122 extern LazyLogModule gPIPNSSLog
;
126 enum Operation
{ reading
, writing
, not_reading_or_writing
};
128 int32_t checkHandshake(int32_t bytesTransfered
, bool wasReading
,
129 PRFileDesc
* ssl_layer_fd
, NSSSocketControl
* socketInfo
);
131 NSSSocketControl
* getSocketInfoIfRunning(PRFileDesc
* fd
, Operation op
) {
132 if (!fd
|| !fd
->lower
|| !fd
->secret
||
133 fd
->identity
!= nsSSLIOLayerHelpers::nsSSLIOLayerIdentity
) {
134 NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
135 PR_SetError(PR_BAD_DESCRIPTOR_ERROR
, 0);
139 NSSSocketControl
* socketInfo
= (NSSSocketControl
*)fd
->secret
;
141 if (socketInfo
->IsCanceled()) {
142 PRErrorCode err
= socketInfo
->GetErrorCode();
144 if (op
== reading
|| op
== writing
) {
145 // We must do TLS intolerance checks for reads and writes, for timeouts
147 (void)checkHandshake(-1, op
== reading
, fd
, socketInfo
);
150 // If we get here, it is probably because cert verification failed and this
151 // is the first I/O attempt since that failure.
160 static PRStatus
nsSSLIOLayerConnect(PRFileDesc
* fd
, const PRNetAddr
* addr
,
161 PRIntervalTime timeout
) {
162 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
163 ("[%p] connecting SSL socket\n", (void*)fd
));
164 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
)) return PR_FAILURE
;
166 PRStatus status
= fd
->lower
->methods
->connect(fd
->lower
, addr
, timeout
);
167 if (status
!= PR_SUCCESS
) {
168 MOZ_LOG(gPIPNSSLog
, LogLevel::Error
,
169 ("[%p] Lower layer connect error: %d\n", (void*)fd
, PR_GetError()));
173 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("[%p] Connect\n", (void*)fd
));
177 void nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString
& hostName
,
181 getSiteKey(hostName
, port
, key
);
183 MutexAutoLock
lock(mutex
);
185 IntoleranceEntry entry
;
186 if (mTLSIntoleranceInfo
.Get(key
, &entry
)) {
187 entry
.AssertInvariant();
188 entry
.tolerant
= std::max(entry
.tolerant
, tolerant
);
189 if (entry
.intolerant
!= 0 && entry
.intolerant
<= entry
.tolerant
) {
190 entry
.intolerant
= entry
.tolerant
+ 1;
191 entry
.intoleranceReason
= 0; // lose the reason
194 entry
.tolerant
= tolerant
;
195 entry
.intolerant
= 0;
196 entry
.intoleranceReason
= 0;
199 entry
.AssertInvariant();
201 mTLSIntoleranceInfo
.InsertOrUpdate(key
, entry
);
204 void nsSSLIOLayerHelpers::forgetIntolerance(const nsACString
& hostName
,
207 getSiteKey(hostName
, port
, key
);
209 MutexAutoLock
lock(mutex
);
211 IntoleranceEntry entry
;
212 if (mTLSIntoleranceInfo
.Get(key
, &entry
)) {
213 entry
.AssertInvariant();
215 entry
.intolerant
= 0;
216 entry
.intoleranceReason
= 0;
218 entry
.AssertInvariant();
219 mTLSIntoleranceInfo
.InsertOrUpdate(key
, entry
);
223 bool nsSSLIOLayerHelpers::fallbackLimitReached(const nsACString
& hostName
,
224 uint16_t intolerant
) {
225 if (isInsecureFallbackSite(hostName
)) {
226 return intolerant
<= SSL_LIBRARY_VERSION_TLS_1_0
;
228 return intolerant
<= mVersionFallbackLimit
;
231 // returns true if we should retry the handshake
232 bool nsSSLIOLayerHelpers::rememberIntolerantAtVersion(
233 const nsACString
& hostName
, uint16_t port
, uint16_t minVersion
,
234 uint16_t intolerant
, PRErrorCode intoleranceReason
) {
235 if (intolerant
<= minVersion
|| fallbackLimitReached(hostName
, intolerant
)) {
236 // We can't fall back any further. Assume that intolerance isn't the issue.
237 forgetIntolerance(hostName
, port
);
242 getSiteKey(hostName
, port
, key
);
244 MutexAutoLock
lock(mutex
);
246 IntoleranceEntry entry
;
247 if (mTLSIntoleranceInfo
.Get(key
, &entry
)) {
248 entry
.AssertInvariant();
249 if (intolerant
<= entry
.tolerant
) {
250 // We already know the server is tolerant at an equal or higher version.
253 if ((entry
.intolerant
!= 0 && intolerant
>= entry
.intolerant
)) {
254 // We already know that the server is intolerant at a lower version.
261 entry
.intolerant
= intolerant
;
262 entry
.intoleranceReason
= intoleranceReason
;
263 entry
.AssertInvariant();
264 mTLSIntoleranceInfo
.InsertOrUpdate(key
, entry
);
269 void nsSSLIOLayerHelpers::adjustForTLSIntolerance(
270 const nsACString
& hostName
, uint16_t port
,
271 /*in/out*/ SSLVersionRange
& range
) {
272 IntoleranceEntry entry
;
276 getSiteKey(hostName
, port
, key
);
278 MutexAutoLock
lock(mutex
);
279 if (!mTLSIntoleranceInfo
.Get(key
, &entry
)) {
284 entry
.AssertInvariant();
286 if (entry
.intolerant
!= 0) {
287 // We've tried connecting at a higher range but failed, so try at the
288 // version we haven't tried yet, unless we have reached the minimum.
289 if (range
.min
< entry
.intolerant
) {
290 range
.max
= entry
.intolerant
- 1;
295 PRErrorCode
nsSSLIOLayerHelpers::getIntoleranceReason(
296 const nsACString
& hostName
, uint16_t port
) {
297 IntoleranceEntry entry
;
301 getSiteKey(hostName
, port
, key
);
303 MutexAutoLock
lock(mutex
);
304 if (!mTLSIntoleranceInfo
.Get(key
, &entry
)) {
309 entry
.AssertInvariant();
310 return entry
.intoleranceReason
;
313 bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized
= false;
314 PRDescIdentity
nsSSLIOLayerHelpers::nsSSLIOLayerIdentity
;
315 PRDescIdentity
nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity
;
316 PRIOMethods
nsSSLIOLayerHelpers::nsSSLIOLayerMethods
;
317 PRIOMethods
nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods
;
319 static PRStatus
nsSSLIOLayerClose(PRFileDesc
* fd
) {
324 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("[%p] Shutting down socket", fd
));
326 // Take the owning reference from the layer. See the corresponding comment in
327 // nsSSLIOLayerAddToSocket where this gets set.
328 RefPtr
<NSSSocketControl
> socketInfo(
329 already_AddRefed((NSSSocketControl
*)fd
->secret
));
330 fd
->secret
= nullptr;
335 return socketInfo
->CloseSocketAndDestroy();
338 #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
339 // Dumps a (potentially binary) buffer using SSM_DEBUG. (We could have used
340 // the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)
341 # define DUMPBUF_LINESIZE 24
342 static void nsDumpBuffer(unsigned char* buf
, int len
) {
343 char hexbuf
[DUMPBUF_LINESIZE
* 3 + 1];
344 char chrbuf
[DUMPBUF_LINESIZE
+ 1];
345 static const char* hex
= "0123456789abcdef";
351 if (len
== 0) return;
352 hexbuf
[DUMPBUF_LINESIZE
* 3] = '\0';
353 chrbuf
[DUMPBUF_LINESIZE
] = '\0';
354 (void)memset(hexbuf
, 0x20, DUMPBUF_LINESIZE
* 3);
355 (void)memset(chrbuf
, 0x20, DUMPBUF_LINESIZE
);
362 if (l
== DUMPBUF_LINESIZE
) {
363 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("%s%s\n", hexbuf
, chrbuf
));
364 (void)memset(hexbuf
, 0x20, DUMPBUF_LINESIZE
* 3);
365 (void)memset(chrbuf
, 0x20, DUMPBUF_LINESIZE
);
371 // Convert a character to hex.
372 *h
++ = hex
[(ch
>> 4) & 0xf];
373 *h
++ = hex
[ch
& 0xf];
376 // Put the character (if it's printable) into the character buffer.
377 if ((ch
>= 0x20) && (ch
<= 0x7e)) {
385 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("%s%s\n", hexbuf
, chrbuf
));
388 # define DEBUG_DUMP_BUFFER(buf, len) nsDumpBuffer(buf, len)
390 # define DEBUG_DUMP_BUFFER(buf, len)
395 uint32_t tlsIntoleranceTelemetryBucket(PRErrorCode err
) {
396 // returns a numeric code for where we track various errors in telemetry
397 // only errors that cause version fallback are tracked,
398 // so this is also used to determine which errors can cause version fallback
400 case SSL_ERROR_BAD_MAC_ALERT
:
402 case SSL_ERROR_BAD_MAC_READ
:
404 case SSL_ERROR_HANDSHAKE_FAILURE_ALERT
:
406 case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT
:
408 case SSL_ERROR_ILLEGAL_PARAMETER_ALERT
:
410 case SSL_ERROR_NO_CYPHER_OVERLAP
:
412 case SSL_ERROR_UNSUPPORTED_VERSION
:
414 case SSL_ERROR_PROTOCOL_VERSION_ALERT
:
416 case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE
:
418 case SSL_ERROR_DECODE_ERROR_ALERT
:
420 case PR_CONNECT_RESET_ERROR
:
422 case PR_END_OF_FILE_ERROR
:
424 case SSL_ERROR_INTERNAL_ERROR_ALERT
:
431 bool retryDueToTLSIntolerance(PRErrorCode err
, NSSSocketControl
* socketInfo
) {
432 // This function is supposed to decide which error codes should
433 // be used to conclude server is TLS intolerant.
434 // Note this only happens during the initial SSL handshake.
436 if (StaticPrefs::security_tls_ech_disable_grease_on_fallback() &&
437 socketInfo
->GetEchExtensionStatus() == EchExtensionStatus::kGREASE
) {
438 // Don't record any intolerances if we used ECH GREASE but force a retry.
442 if (!socketInfo
->IsPreliminaryHandshakeDone() &&
443 !socketInfo
->HasTls13HandshakeSecrets() && socketInfo
->SentMlkemShare()) {
444 nsAutoCString errorName
;
445 const char* prErrorName
= PR_ErrorToName(err
);
447 errorName
.AppendASCII(prErrorName
);
449 mozilla::glean::tls::xyber_intolerance_reason
.Get(errorName
).Add(1);
450 // Don't record version intolerance if we sent mlkem768x25519, just force a
455 SSLVersionRange range
= socketInfo
->GetTLSVersionRange();
457 if (err
== SSL_ERROR_UNSUPPORTED_VERSION
&&
458 range
.min
== SSL_LIBRARY_VERSION_TLS_1_0
) {
459 socketInfo
->SetSecurityState(nsIWebProgressListener::STATE_IS_INSECURE
|
460 nsIWebProgressListener::STATE_USES_SSL_3
);
463 // NSS will return SSL_ERROR_RX_MALFORMED_SERVER_HELLO if anti-downgrade
464 // detected the downgrade.
465 if (err
== SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT
||
466 err
== SSL_ERROR_RX_MALFORMED_SERVER_HELLO
) {
467 // This is a clear signal that we've fallen back too many versions. Treat
468 // this as a hard failure, but forget any intolerance so that later attempts
469 // don't use this version (i.e., range.max) and trigger the error again.
471 // First, track the original cause of the version fallback. This uses the
472 // same buckets as the telemetry below, except that bucket 0 will include
473 // all cases where there wasn't an original reason.
474 PRErrorCode originalReason
= socketInfo
->GetTLSIntoleranceReason();
475 Telemetry::Accumulate(Telemetry::SSL_VERSION_FALLBACK_INAPPROPRIATE
,
476 tlsIntoleranceTelemetryBucket(originalReason
));
478 socketInfo
->ForgetTLSIntolerance();
483 // When not using a proxy we'll see a connection reset error.
484 // When using a proxy, we'll see an end of file error.
486 // Don't allow STARTTLS connections to fall back on connection resets or
488 if ((err
== PR_CONNECT_RESET_ERROR
|| err
== PR_END_OF_FILE_ERROR
) &&
489 socketInfo
->GetForSTARTTLS()) {
493 uint32_t reason
= tlsIntoleranceTelemetryBucket(err
);
498 Telemetry::HistogramID pre
;
499 Telemetry::HistogramID post
;
501 case SSL_LIBRARY_VERSION_TLS_1_3
:
502 pre
= Telemetry::SSL_TLS13_INTOLERANCE_REASON_PRE
;
503 post
= Telemetry::SSL_TLS13_INTOLERANCE_REASON_POST
;
505 case SSL_LIBRARY_VERSION_TLS_1_2
:
506 pre
= Telemetry::SSL_TLS12_INTOLERANCE_REASON_PRE
;
507 post
= Telemetry::SSL_TLS12_INTOLERANCE_REASON_POST
;
509 case SSL_LIBRARY_VERSION_TLS_1_1
:
510 pre
= Telemetry::SSL_TLS11_INTOLERANCE_REASON_PRE
;
511 post
= Telemetry::SSL_TLS11_INTOLERANCE_REASON_POST
;
513 case SSL_LIBRARY_VERSION_TLS_1_0
:
514 pre
= Telemetry::SSL_TLS10_INTOLERANCE_REASON_PRE
;
515 post
= Telemetry::SSL_TLS10_INTOLERANCE_REASON_POST
;
518 MOZ_CRASH("impossible TLS version");
522 // The difference between _PRE and _POST represents how often we avoided
523 // TLS intolerance fallback due to remembered tolerance.
524 Telemetry::Accumulate(pre
, reason
);
526 if (!socketInfo
->RememberTLSIntolerant(err
)) {
530 Telemetry::Accumulate(post
, reason
);
535 // Ensure that we haven't added too many errors to fit.
536 static_assert((SSL_ERROR_END_OF_LIST
- SSL_ERROR_BASE
) <= 256,
537 "too many SSL errors");
538 static_assert((SEC_ERROR_END_OF_LIST
- SEC_ERROR_BASE
) <= 256,
539 "too many SEC errors");
540 static_assert((PR_MAX_ERROR
- PR_NSPR_ERROR_BASE
) <= 128,
541 "too many NSPR errors");
542 static_assert((mozilla::pkix::ERROR_BASE
- mozilla::pkix::END_OF_LIST
) < 31,
543 "too many moz::pkix errors");
545 static void reportHandshakeResult(int32_t bytesTransferred
, bool wasReading
,
547 NSSSocketControl
* socketInfo
) {
550 // A negative bytesTransferred or a 0 read are errors.
551 if (bytesTransferred
> 0) {
553 } else if ((bytesTransferred
== 0) && !wasReading
) {
554 // PR_Write() is defined to never return 0, but let's make sure.
555 // https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSPR/Reference/PR_Write.
558 } else if (IS_SSL_ERROR(err
)) {
559 bucket
= err
- SSL_ERROR_BASE
;
560 MOZ_ASSERT(bucket
> 0); // SSL_ERROR_EXPORT_ONLY_SERVER isn't used.
561 } else if (IS_SEC_ERROR(err
)) {
562 bucket
= (err
- SEC_ERROR_BASE
) + 256;
563 } else if ((err
>= PR_NSPR_ERROR_BASE
) && (err
< PR_MAX_ERROR
)) {
564 bucket
= (err
- PR_NSPR_ERROR_BASE
) + 512;
565 } else if ((err
>= mozilla::pkix::ERROR_BASE
) &&
566 (err
< mozilla::pkix::ERROR_LIMIT
)) {
567 bucket
= (err
- mozilla::pkix::ERROR_BASE
) + 640;
572 uint32_t flags
= socketInfo
->GetProviderFlags();
573 if (!(flags
& nsISocketProvider::IS_RETRY
)) {
574 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT_FIRST_TRY
, bucket
);
577 if (flags
& nsISocketProvider::BE_CONSERVATIVE
) {
578 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT_CONSERVATIVE
, bucket
);
581 switch (socketInfo
->GetEchExtensionStatus()) {
582 case EchExtensionStatus::kGREASE
:
583 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT_ECH_GREASE
, bucket
);
585 case EchExtensionStatus::kReal
:
586 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT_ECH
, bucket
);
591 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT
, bucket
);
594 nsCOMPtr
<nsITransportSecurityInfo
> securityInfo
;
595 if (NS_FAILED(socketInfo
->GetSecurityInfo(getter_AddRefs(securityInfo
))) ||
599 // Web Privacy Telemetry for successful connections.
602 bool usedPrivateDNS
= false;
603 success
&= securityInfo
->GetUsedPrivateDNS(&usedPrivateDNS
) == NS_OK
;
605 bool madeOCSPRequest
= false;
606 success
&= securityInfo
->GetMadeOCSPRequests(&madeOCSPRequest
) == NS_OK
;
608 uint16_t protocolVersion
= 0;
609 success
&= securityInfo
->GetProtocolVersion(&protocolVersion
) == NS_OK
;
610 bool usedTLS13
= protocolVersion
== 4;
612 bool usedECH
= false;
613 success
&= securityInfo
->GetIsAcceptedEch(&usedECH
) == NS_OK
;
615 // As bucket is 0 we are reporting the results of a sucessful connection
616 // and so TransportSecurityInfo should be populated. However, this isn't
617 // happening in all cases, see Bug 1789458.
619 uint8_t TLSPrivacyResult
= 0;
620 TLSPrivacyResult
|= usedTLS13
<< 0;
621 TLSPrivacyResult
|= !madeOCSPRequest
<< 1;
622 TLSPrivacyResult
|= usedPrivateDNS
<< 2;
623 TLSPrivacyResult
|= usedECH
<< 3;
625 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_PRIVACY
, TLSPrivacyResult
);
630 // Check the status of the handshake. This is where PSM checks for TLS
631 // intolerance and potentially sets up TLS intolerance fallback by noting the
632 // intolerance, setting the NSPR error to PR_CONNECT_RESET_ERROR, and returning
633 // -1 as the bytes transferred so that necko retries the connection.
634 // Otherwise, PSM returns the bytes transferred unchanged.
635 int32_t checkHandshake(int32_t bytesTransferred
, bool wasReading
,
636 PRFileDesc
* ssl_layer_fd
, NSSSocketControl
* socketInfo
) {
637 const PRErrorCode originalError
= PR_GetError();
639 // If the connection would block, return early.
640 if (bytesTransferred
< 0 && originalError
== PR_WOULD_BLOCK_ERROR
) {
641 PR_SetError(PR_WOULD_BLOCK_ERROR
, 0);
642 return bytesTransferred
;
645 // We only need to do TLS intolerance checking for the first transfer.
646 bool handleHandshakeResultNow
= socketInfo
->IsHandshakePending();
647 if (!handleHandshakeResultNow
) {
648 // If we've encountered an error since the handshake, ensure the socket
649 // control is cancelled, so that getSocketInfoIfRunning will correctly
650 // cause us to fail if another part of Gecko (erroneously) calls an I/O
651 // function (PR_Send/PR_Recv/etc.) again on this socket.
652 if (bytesTransferred
< 0) {
653 if (!socketInfo
->IsCanceled()) {
654 socketInfo
->SetCanceled(originalError
);
656 PR_SetError(originalError
, 0);
658 return bytesTransferred
;
661 // TLS intolerant servers only cause the first transfer to fail, so let's
662 // set the HandshakePending attribute to false so that we don't try this logic
663 // again in a subsequent transfer.
664 socketInfo
->SetHandshakeNotPending();
665 // Report the result once for each handshake. Note that this does not
666 // get handshakes which are cancelled before any reads or writes
668 reportHandshakeResult(bytesTransferred
, wasReading
, originalError
,
671 // If there was no error, return early. The case where we read 0 bytes is not
672 // considered an error by NSS, but PSM interprets this as TLS intolerance, so
673 // we turn it into an error. Writes of 0 bytes are an error, because PR_Write
674 // is never supposed to return 0.
675 if (bytesTransferred
> 0) {
676 return bytesTransferred
;
679 // There was some sort of error. Determine what it was and if we want to
680 // retry the connection due to TLS intolerance.
681 PRErrorCode errorToUse
= originalError
;
682 // Turn zero-length reads into errors and handle zero-length write errors.
683 if (bytesTransferred
== 0) {
685 errorToUse
= PR_END_OF_FILE_ERROR
;
687 errorToUse
= SEC_ERROR_LIBRARY_FAILURE
;
689 bytesTransferred
= -1;
691 bool wantRetry
= retryDueToTLSIntolerance(errorToUse
, socketInfo
);
692 // Set the error on the socket control and cancel it.
693 if (!socketInfo
->IsCanceled()) {
694 socketInfo
->SetCanceled(errorToUse
);
698 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
699 ("[%p] checkHandshake: will retry with lower max TLS version",
701 // Setting the error PR_CONNECT_RESET_ERROR causes necko to retry the
703 PR_SetError(PR_CONNECT_RESET_ERROR
, 0);
705 PR_SetError(originalError
, 0);
708 return bytesTransferred
;
713 static int16_t nsSSLIOLayerPoll(PRFileDesc
* fd
, int16_t in_flags
,
714 int16_t* out_flags
) {
716 NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
722 NSSSocketControl
* socketInfo
=
723 getSocketInfoIfRunning(fd
, not_reading_or_writing
);
726 // If we get here, it is probably because certificate validation failed
727 // and this is the first I/O operation after the failure.
729 gPIPNSSLog
, LogLevel::Debug
,
730 ("[%p] polling SSL socket right after certificate verification failed "
731 "or NSS shutdown or SDR logout %d\n",
734 MOZ_ASSERT(in_flags
& PR_POLL_EXCEPT
,
735 "Caller did not poll for EXCEPT (canceled)");
736 // Since this poll method cannot return errors, we want the caller to call
737 // PR_Send/PR_Recv right away to get the error, so we tell that we are
738 // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
739 *out_flags
= in_flags
| PR_POLL_EXCEPT
; // see also bug 480619
743 MOZ_LOG(gPIPNSSLog
, LogLevel::Verbose
,
744 (socketInfo
->IsWaitingForCertVerification()
745 ? "[%p] polling SSL socket during certificate verification "
747 : "[%p] poll SSL socket using lower %d\n",
750 socketInfo
->MaybeDispatchSelectClientAuthCertificate();
752 // We want the handshake to continue during certificate validation, so we
753 // don't need to do anything special here. libssl automatically blocks when
754 // it reaches any point that would be unsafe to send/receive something before
755 // cert validation is complete.
756 int16_t result
= fd
->lower
->methods
->poll(fd
->lower
, in_flags
, out_flags
);
757 MOZ_LOG(gPIPNSSLog
, LogLevel::Verbose
,
758 ("[%p] poll SSL socket returned %d\n", (void*)fd
, (int)result
));
762 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers(PublicOrPrivate aPublicOrPrivate
,
764 : mVersionFallbackLimit(SSL_LIBRARY_VERSION_TLS_1_0
),
765 mPublicOrPrivate(aPublicOrPrivate
),
766 mutex("nsSSLIOLayerHelpers.mutex"),
767 mTlsFlags(aTlsFlags
) {}
769 // PSMAvailable and PSMAvailable64 are reachable, but they're unimplemented in
770 // PSM, so we set an error and return -1.
771 static int32_t PSMAvailable(PRFileDesc
*) {
772 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
776 static int64_t PSMAvailable64(PRFileDesc
*) {
777 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
781 static PRStatus
PSMGetsockname(PRFileDesc
* fd
, PRNetAddr
* addr
) {
782 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
)) return PR_FAILURE
;
784 return fd
->lower
->methods
->getsockname(fd
->lower
, addr
);
787 static PRStatus
PSMGetpeername(PRFileDesc
* fd
, PRNetAddr
* addr
) {
788 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
)) return PR_FAILURE
;
790 return fd
->lower
->methods
->getpeername(fd
->lower
, addr
);
793 static PRStatus
PSMGetsocketoption(PRFileDesc
* fd
, PRSocketOptionData
* data
) {
794 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
)) return PR_FAILURE
;
796 return fd
->lower
->methods
->getsocketoption(fd
, data
);
799 static PRStatus
PSMSetsocketoption(PRFileDesc
* fd
,
800 const PRSocketOptionData
* data
) {
801 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
)) return PR_FAILURE
;
803 return fd
->lower
->methods
->setsocketoption(fd
, data
);
806 static int32_t PSMRecv(PRFileDesc
* fd
, void* buf
, int32_t amount
, int flags
,
807 PRIntervalTime timeout
) {
808 NSSSocketControl
* socketInfo
= getSocketInfoIfRunning(fd
, reading
);
809 if (!socketInfo
) return -1;
811 if (flags
!= PR_MSG_PEEK
&& flags
!= 0) {
812 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
817 fd
->lower
->methods
->recv(fd
->lower
, buf
, amount
, flags
, timeout
);
819 MOZ_LOG(gPIPNSSLog
, LogLevel::Verbose
,
820 ("[%p] read %d bytes\n", (void*)fd
, bytesRead
));
822 #ifdef DEBUG_SSL_VERBOSE
823 DEBUG_DUMP_BUFFER((unsigned char*)buf
, bytesRead
);
826 return checkHandshake(bytesRead
, true, fd
, socketInfo
);
829 static int32_t PSMSend(PRFileDesc
* fd
, const void* buf
, int32_t amount
,
830 int flags
, PRIntervalTime timeout
) {
831 NSSSocketControl
* socketInfo
= getSocketInfoIfRunning(fd
, writing
);
832 if (!socketInfo
) return -1;
835 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, 0);
839 #ifdef DEBUG_SSL_VERBOSE
840 DEBUG_DUMP_BUFFER((unsigned char*)buf
, amount
);
843 if (socketInfo
->IsShortWritePending() && amount
> 0) {
844 // We got "SSL short write" last time, try to flush the pending byte.
846 socketInfo
->CheckShortWrittenBuffer(static_cast<const unsigned char*>(buf
),
850 buf
= socketInfo
->GetShortWritePendingByteRef();
853 MOZ_LOG(gPIPNSSLog
, LogLevel::Verbose
,
854 ("[%p] pushing 1 byte after SSL short write", fd
));
857 int32_t bytesWritten
=
858 fd
->lower
->methods
->send(fd
->lower
, buf
, amount
, flags
, timeout
);
860 // NSS indicates that it can't write all requested data (due to network
861 // congestion, for example) by returning either one less than the amount
862 // of data requested or 16383, if the requested amount is greater than
863 // 16384. We refer to this as a "short write". If we simply returned
864 // the amount that NSS did write, the layer above us would then call
865 // PSMSend with a very small amount of data (often 1). This is inefficient
866 // and can lead to alternating between sending large packets and very small
867 // packets. To prevent this, we alert the layer calling us that the operation
868 // would block and that it should be retried later, with the same data.
869 // When it does, we tell NSS to write the remaining byte it didn't write
870 // in the previous call. We then return the total number of bytes written,
871 // which is the number that caused the short write plus the additional byte
872 // we just wrote out.
874 // The 16384 value is based on libssl's maximum buffer size:
875 // MAX_FRAGMENT_LENGTH - 1
877 // It's in a private header, though, filed bug 1394822 to expose it.
878 static const int32_t kShortWrite16k
= 16383;
880 if ((amount
> 1 && bytesWritten
== (amount
- 1)) ||
881 (amount
> kShortWrite16k
&& bytesWritten
== kShortWrite16k
)) {
882 // This is indication of an "SSL short write", block to force retry.
883 socketInfo
->SetShortWritePending(
884 bytesWritten
+ 1, // The amount to return after the flush
885 *(static_cast<const unsigned char*>(buf
) + bytesWritten
));
888 gPIPNSSLog
, LogLevel::Verbose
,
889 ("[%p] indicated SSL short write for %d bytes (written just %d bytes)",
890 fd
, amount
, bytesWritten
));
893 PR_SetError(PR_WOULD_BLOCK_ERROR
, 0);
896 socketInfo
->RememberShortWrittenBuffer(
897 static_cast<const unsigned char*>(buf
));
900 } else if (socketInfo
->IsShortWritePending() && bytesWritten
== 1) {
901 // We have now flushed all pending data in the SSL socket
902 // after the indicated short write. Tell the upper layer
903 // it has sent all its data now.
904 MOZ_LOG(gPIPNSSLog
, LogLevel::Verbose
,
905 ("[%p] finished SSL short write", fd
));
907 bytesWritten
= socketInfo
->ResetShortWritePending();
910 MOZ_LOG(gPIPNSSLog
, LogLevel::Verbose
,
911 ("[%p] wrote %d bytes\n", fd
, bytesWritten
));
913 return checkHandshake(bytesWritten
, false, fd
, socketInfo
);
916 static PRStatus
PSMBind(PRFileDesc
* fd
, const PRNetAddr
* addr
) {
917 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
)) return PR_FAILURE
;
919 return fd
->lower
->methods
->bind(fd
->lower
, addr
);
922 static int32_t nsSSLIOLayerRead(PRFileDesc
* fd
, void* buf
, int32_t amount
) {
923 return PSMRecv(fd
, buf
, amount
, 0, PR_INTERVAL_NO_TIMEOUT
);
926 static int32_t nsSSLIOLayerWrite(PRFileDesc
* fd
, const void* buf
,
928 return PSMSend(fd
, buf
, amount
, 0, PR_INTERVAL_NO_TIMEOUT
);
931 static PRStatus
PSMConnectcontinue(PRFileDesc
* fd
, int16_t out_flags
) {
932 if (!getSocketInfoIfRunning(fd
, not_reading_or_writing
)) {
936 return fd
->lower
->methods
->connectcontinue(fd
, out_flags
);
939 NS_IMPL_ISUPPORTS(nsSSLIOLayerHelpers
, nsIObserver
)
942 nsSSLIOLayerHelpers::Observe(nsISupports
* aSubject
, const char* aTopic
,
943 const char16_t
* someData
) {
944 if (nsCRT::strcmp(aTopic
, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
) == 0) {
945 NS_ConvertUTF16toUTF8
prefName(someData
);
947 if (prefName
.EqualsLiteral("security.tls.version.fallback-limit")) {
948 loadVersionFallbackLimit();
949 } else if (prefName
.EqualsLiteral("security.tls.insecure_fallback_hosts")) {
950 initInsecureFallbackSites();
952 } else if (nsCRT::strcmp(aTopic
, "last-pb-context-exited") == 0) {
958 void nsSSLIOLayerHelpers::GlobalInit() {
959 MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
960 gPublicSSLIOLayerHelpers
= new nsSSLIOLayerHelpers(PublicOrPrivate::Public
);
961 gPublicSSLIOLayerHelpers
->Init();
962 gPrivateSSLIOLayerHelpers
= new nsSSLIOLayerHelpers(PublicOrPrivate::Private
);
963 gPrivateSSLIOLayerHelpers
->Init();
967 void nsSSLIOLayerHelpers::GlobalCleanup() {
968 MOZ_ASSERT(NS_IsMainThread(), "Not on main thread");
970 if (gPrivateSSLIOLayerHelpers
) {
971 gPrivateSSLIOLayerHelpers
= nullptr;
974 if (gPublicSSLIOLayerHelpers
) {
975 gPublicSSLIOLayerHelpers
= nullptr;
979 already_AddRefed
<nsSSLIOLayerHelpers
> PublicSSLIOLayerHelpers() {
980 return do_AddRef(gPublicSSLIOLayerHelpers
);
983 already_AddRefed
<nsSSLIOLayerHelpers
> PrivateSSLIOLayerHelpers() {
984 return do_AddRef(gPrivateSSLIOLayerHelpers
);
987 static int32_t PlaintextRecv(PRFileDesc
* fd
, void* buf
, int32_t amount
,
988 int flags
, PRIntervalTime timeout
) {
989 NSSSocketControl
* socketInfo
= nullptr;
992 fd
->lower
->methods
->recv(fd
->lower
, buf
, amount
, flags
, timeout
);
993 if (fd
->identity
== nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity
) {
994 socketInfo
= (NSSSocketControl
*)fd
->secret
;
997 if ((bytesRead
> 0) && socketInfo
) {
998 socketInfo
->AddPlaintextBytesRead(bytesRead
);
1003 nsSSLIOLayerHelpers::~nsSSLIOLayerHelpers() {
1004 Preferences::RemoveObserver(this, "security.tls.version.fallback-limit");
1005 Preferences::RemoveObserver(this, "security.tls.insecure_fallback_hosts");
1008 template <typename R
, R return_value
, typename
... Args
>
1009 static R
InvalidPRIOMethod(Args
...) {
1010 MOZ_ASSERT_UNREACHABLE("I/O method is invalid");
1011 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
1012 return return_value
;
1015 nsresult
nsSSLIOLayerHelpers::Init() {
1016 if (!nsSSLIOLayerInitialized
) {
1017 MOZ_ASSERT(NS_IsMainThread());
1018 nsSSLIOLayerInitialized
= true;
1019 nsSSLIOLayerIdentity
= PR_GetUniqueIdentity("NSS layer");
1020 nsSSLIOLayerMethods
= *PR_GetDefaultIOMethods();
1022 nsSSLIOLayerMethods
.fsync
=
1023 InvalidPRIOMethod
<PRStatus
, PR_FAILURE
, PRFileDesc
*>;
1024 nsSSLIOLayerMethods
.seek
=
1025 InvalidPRIOMethod
<int32_t, -1, PRFileDesc
*, int32_t, PRSeekWhence
>;
1026 nsSSLIOLayerMethods
.seek64
=
1027 InvalidPRIOMethod
<int64_t, -1, PRFileDesc
*, int64_t, PRSeekWhence
>;
1028 nsSSLIOLayerMethods
.fileInfo
=
1029 InvalidPRIOMethod
<PRStatus
, PR_FAILURE
, PRFileDesc
*, PRFileInfo
*>;
1030 nsSSLIOLayerMethods
.fileInfo64
=
1031 InvalidPRIOMethod
<PRStatus
, PR_FAILURE
, PRFileDesc
*, PRFileInfo64
*>;
1032 nsSSLIOLayerMethods
.writev
=
1033 InvalidPRIOMethod
<int32_t, -1, PRFileDesc
*, const PRIOVec
*, int32_t,
1035 nsSSLIOLayerMethods
.accept
=
1036 InvalidPRIOMethod
<PRFileDesc
*, nullptr, PRFileDesc
*, PRNetAddr
*,
1038 nsSSLIOLayerMethods
.listen
=
1039 InvalidPRIOMethod
<PRStatus
, PR_FAILURE
, PRFileDesc
*, int>;
1040 nsSSLIOLayerMethods
.shutdown
=
1041 InvalidPRIOMethod
<PRStatus
, PR_FAILURE
, PRFileDesc
*, int>;
1042 nsSSLIOLayerMethods
.recvfrom
=
1043 InvalidPRIOMethod
<int32_t, -1, PRFileDesc
*, void*, int32_t, int,
1044 PRNetAddr
*, PRIntervalTime
>;
1045 nsSSLIOLayerMethods
.sendto
=
1046 InvalidPRIOMethod
<int32_t, -1, PRFileDesc
*, const void*, int32_t, int,
1047 const PRNetAddr
*, PRIntervalTime
>;
1048 nsSSLIOLayerMethods
.acceptread
=
1049 InvalidPRIOMethod
<int32_t, -1, PRFileDesc
*, PRFileDesc
**, PRNetAddr
**,
1050 void*, int32_t, PRIntervalTime
>;
1051 nsSSLIOLayerMethods
.transmitfile
=
1052 InvalidPRIOMethod
<int32_t, -1, PRFileDesc
*, PRFileDesc
*, const void*,
1053 int32_t, PRTransmitFileFlags
, PRIntervalTime
>;
1054 nsSSLIOLayerMethods
.sendfile
=
1055 InvalidPRIOMethod
<int32_t, -1, PRFileDesc
*, PRSendFileData
*,
1056 PRTransmitFileFlags
, PRIntervalTime
>;
1058 nsSSLIOLayerMethods
.available
= PSMAvailable
;
1059 nsSSLIOLayerMethods
.available64
= PSMAvailable64
;
1060 nsSSLIOLayerMethods
.getsockname
= PSMGetsockname
;
1061 nsSSLIOLayerMethods
.getpeername
= PSMGetpeername
;
1062 nsSSLIOLayerMethods
.getsocketoption
= PSMGetsocketoption
;
1063 nsSSLIOLayerMethods
.setsocketoption
= PSMSetsocketoption
;
1064 nsSSLIOLayerMethods
.recv
= PSMRecv
;
1065 nsSSLIOLayerMethods
.send
= PSMSend
;
1066 nsSSLIOLayerMethods
.connectcontinue
= PSMConnectcontinue
;
1067 nsSSLIOLayerMethods
.bind
= PSMBind
;
1069 nsSSLIOLayerMethods
.connect
= nsSSLIOLayerConnect
;
1070 nsSSLIOLayerMethods
.close
= nsSSLIOLayerClose
;
1071 nsSSLIOLayerMethods
.write
= nsSSLIOLayerWrite
;
1072 nsSSLIOLayerMethods
.read
= nsSSLIOLayerRead
;
1073 nsSSLIOLayerMethods
.poll
= nsSSLIOLayerPoll
;
1075 nsSSLPlaintextLayerIdentity
= PR_GetUniqueIdentity("Plaintxext PSM layer");
1076 nsSSLPlaintextLayerMethods
= *PR_GetDefaultIOMethods();
1077 nsSSLPlaintextLayerMethods
.recv
= PlaintextRecv
;
1080 loadVersionFallbackLimit();
1082 // non main thread helpers will need to use defaults
1083 if (NS_IsMainThread()) {
1084 initInsecureFallbackSites();
1086 Preferences::AddStrongObserver(this, "security.tls.version.fallback-limit");
1088 // Changes to the allowlist on the public side will update the pref.
1089 // Don't propagate the changes to the private side.
1090 Preferences::AddStrongObserver(this,
1091 "security.tls.insecure_fallback_hosts");
1093 nsCOMPtr
<nsIObserverService
> obsSvc
=
1094 mozilla::services::GetObserverService();
1096 obsSvc
->AddObserver(this, "last-pb-context-exited", false);
1100 MOZ_ASSERT(mTlsFlags
, "Only per socket version can ignore prefs");
1106 void nsSSLIOLayerHelpers::loadVersionFallbackLimit() {
1107 // see nsNSSComponent::SetEnabledTLSVersions for pref handling rules
1108 uint32_t limit
= StaticPrefs::security_tls_version_fallback_limit();
1110 // set fallback limit if it is set in the tls flags
1111 uint32_t tlsFlagsFallbackLimit
= getTLSProviderFlagFallbackLimit(mTlsFlags
);
1113 if (tlsFlagsFallbackLimit
) {
1114 limit
= tlsFlagsFallbackLimit
;
1115 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1116 ("loadVersionFallbackLimit overriden by tlsFlags %d\n", limit
));
1119 SSLVersionRange defaults
= {SSL_LIBRARY_VERSION_TLS_1_2
,
1120 SSL_LIBRARY_VERSION_TLS_1_2
};
1121 SSLVersionRange filledInRange
;
1122 nsNSSComponent::FillTLSVersionRange(filledInRange
, limit
, limit
, defaults
);
1123 if (filledInRange
.max
< SSL_LIBRARY_VERSION_TLS_1_2
) {
1124 filledInRange
.max
= SSL_LIBRARY_VERSION_TLS_1_2
;
1127 mVersionFallbackLimit
= filledInRange
.max
;
1130 void nsSSLIOLayerHelpers::clearStoredData() {
1131 MOZ_ASSERT(NS_IsMainThread());
1132 initInsecureFallbackSites();
1134 MutexAutoLock
lock(mutex
);
1135 mTLSIntoleranceInfo
.Clear();
1138 void nsSSLIOLayerHelpers::setInsecureFallbackSites(const nsCString
& str
) {
1139 MutexAutoLock
lock(mutex
);
1141 mInsecureFallbackSites
.Clear();
1143 for (const nsACString
& host
: nsCCharSeparatedTokenizer(str
, ',').ToRange()) {
1144 if (!host
.IsEmpty()) {
1145 mInsecureFallbackSites
.PutEntry(host
);
1150 void nsSSLIOLayerHelpers::initInsecureFallbackSites() {
1151 MOZ_ASSERT(NS_IsMainThread());
1152 nsAutoCString insecureFallbackHosts
;
1153 Preferences::GetCString("security.tls.insecure_fallback_hosts",
1154 insecureFallbackHosts
);
1155 setInsecureFallbackSites(insecureFallbackHosts
);
1158 bool nsSSLIOLayerHelpers::isPublic() const {
1159 return mPublicOrPrivate
== PublicOrPrivate::Public
;
1162 class FallbackPrefRemover final
: public Runnable
{
1164 explicit FallbackPrefRemover(const nsACString
& aHost
)
1165 : mozilla::Runnable("FallbackPrefRemover"), mHost(aHost
) {}
1166 NS_IMETHOD
Run() override
;
1173 FallbackPrefRemover::Run() {
1174 MOZ_ASSERT(NS_IsMainThread());
1175 nsAutoCString oldValue
;
1176 Preferences::GetCString("security.tls.insecure_fallback_hosts", oldValue
);
1178 for (const nsACString
& host
:
1179 nsCCharSeparatedTokenizer(oldValue
, ',').ToRange()) {
1180 if (host
.Equals(mHost
)) {
1183 if (!newValue
.IsEmpty()) {
1184 newValue
.Append(',');
1186 newValue
.Append(host
);
1188 Preferences::SetCString("security.tls.insecure_fallback_hosts", newValue
);
1192 void nsSSLIOLayerHelpers::removeInsecureFallbackSite(const nsACString
& hostname
,
1194 forgetIntolerance(hostname
, port
);
1196 MutexAutoLock
lock(mutex
);
1197 if (!mInsecureFallbackSites
.Contains(hostname
)) {
1200 mInsecureFallbackSites
.RemoveEntry(hostname
);
1205 RefPtr
<Runnable
> runnable
= new FallbackPrefRemover(hostname
);
1206 if (NS_IsMainThread()) {
1209 NS_DispatchToMainThread(runnable
);
1213 bool nsSSLIOLayerHelpers::isInsecureFallbackSite(const nsACString
& hostname
) {
1214 MutexAutoLock
lock(mutex
);
1215 return mInsecureFallbackSites
.Contains(hostname
);
1218 nsresult
nsSSLIOLayerNewSocket(int32_t family
, const char* host
, int32_t port
,
1219 nsIProxyInfo
* proxy
,
1220 const OriginAttributes
& originAttributes
,
1222 nsITLSSocketControl
** tlsSocketControl
,
1223 bool forSTARTTLS
, uint32_t flags
,
1224 uint32_t tlsFlags
) {
1225 PRFileDesc
* sock
= PR_OpenTCPSocket(family
);
1226 if (!sock
) return NS_ERROR_OUT_OF_MEMORY
;
1229 nsSSLIOLayerAddToSocket(family
, host
, port
, proxy
, originAttributes
, sock
,
1230 tlsSocketControl
, forSTARTTLS
, flags
, tlsFlags
);
1231 if (NS_FAILED(rv
)) {
1240 static PRFileDesc
* nsSSLIOLayerImportFD(PRFileDesc
* fd
,
1241 NSSSocketControl
* infoObject
,
1242 const char* host
, bool haveHTTPSProxy
) {
1243 // Memory allocated here is released when fd is closed, regardless of the
1244 // success of this function.
1245 PRFileDesc
* sslSock
= SSL_ImportFD(nullptr, fd
);
1249 if (SSL_SetPKCS11PinArg(sslSock
, infoObject
) != SECSuccess
) {
1252 if (SSL_HandshakeCallback(sslSock
, HandshakeCallback
, infoObject
) !=
1256 if (SSL_SecretCallback(sslSock
, SecretCallback
, infoObject
) != SECSuccess
) {
1259 if (SSL_SetCanFalseStartCallback(sslSock
, CanFalseStartCallback
,
1260 infoObject
) != SECSuccess
) {
1264 // Disable this hook if we connect anonymously. See bug 466080.
1265 uint32_t flags
= infoObject
->GetProviderFlags();
1266 SSLGetClientAuthData clientAuthDataHook
= SSLGetClientAuthDataHook
;
1267 // Provide the client cert to HTTPS proxy no matter if it is anonymous.
1268 if (flags
& nsISocketProvider::ANONYMOUS_CONNECT
&& !haveHTTPSProxy
&&
1269 !(flags
& nsISocketProvider::ANONYMOUS_CONNECT_ALLOW_CLIENT_CERT
)) {
1270 clientAuthDataHook
= nullptr;
1272 if (SSL_GetClientAuthDataHook(sslSock
, clientAuthDataHook
, infoObject
) !=
1277 if (SSL_AuthCertificateHook(sslSock
, AuthCertificateHook
, infoObject
) !=
1281 if (SSL_SetURL(sslSock
, host
) != SECSuccess
) {
1288 // Please change getSignatureName in nsNSSCallbacks.cpp when changing the list
1289 // here. See NOTE at SSL_SignatureSchemePrefSet call site.
1290 static const SSLSignatureScheme sEnabledSignatureSchemes
[] = {
1291 ssl_sig_ecdsa_secp256r1_sha256
,
1292 ssl_sig_ecdsa_secp384r1_sha384
,
1293 ssl_sig_ecdsa_secp521r1_sha512
,
1294 ssl_sig_rsa_pss_sha256
,
1295 ssl_sig_rsa_pss_sha384
,
1296 ssl_sig_rsa_pss_sha512
,
1297 ssl_sig_rsa_pkcs1_sha256
,
1298 ssl_sig_rsa_pkcs1_sha384
,
1299 ssl_sig_rsa_pkcs1_sha512
,
1300 #if !defined(EARLY_BETA_OR_EARLIER)
1303 ssl_sig_rsa_pkcs1_sha1
,
1306 enum CertificateCompressionAlgorithms
{
1312 void GatherCertificateCompressionTelemetry(SECStatus rv
,
1313 CertificateCompressionAlgorithms alg
,
1314 PRUint64 actualCertLen
,
1315 PRUint64 encodedCertLen
) {
1316 nsAutoCString decoder
;
1320 decoder
.AssignLiteral("zlib");
1323 decoder
.AssignLiteral("brotli");
1326 decoder
.AssignLiteral("zstd");
1330 if (rv
!= SECSuccess
) {
1331 mozilla::glean::cert_compression::failures
.Get(decoder
).Add(1);
1334 // Glam requires us to send 0 in case of success.
1335 mozilla::glean::cert_compression::failures
.Get(decoder
).Add(0);
1338 SECStatus
zlibCertificateDecode(const SECItem
* input
, unsigned char* output
,
1339 size_t outputLen
, size_t* usedLen
) {
1340 SECStatus rv
= SECFailure
;
1341 if (!input
|| !input
->data
|| input
->len
== 0 || !output
|| outputLen
== 0) {
1342 PR_SetError(SEC_ERROR_INVALID_ARGS
, 0);
1348 if (inflateInit(&strm
) != Z_OK
) {
1349 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
1353 auto cleanup
= MakeScopeExit([&] {
1354 GatherCertificateCompressionTelemetry(rv
, zlib
, *usedLen
, input
->len
);
1355 (void)inflateEnd(&strm
);
1358 strm
.avail_in
= input
->len
;
1359 strm
.next_in
= input
->data
;
1361 strm
.avail_out
= outputLen
;
1362 strm
.next_out
= output
;
1364 int ret
= inflate(&strm
, Z_FINISH
);
1365 bool ok
= ret
== Z_STREAM_END
&& strm
.avail_in
== 0 && strm
.avail_out
== 0;
1367 PR_SetError(SEC_ERROR_BAD_DATA
, 0);
1371 *usedLen
= strm
.total_out
;
1376 SECStatus
brotliCertificateDecode(const SECItem
* input
, unsigned char* output
,
1377 size_t outputLen
, size_t* usedLen
) {
1378 SECStatus rv
= SECFailure
;
1380 if (!input
|| !input
->data
|| input
->len
== 0 || !output
|| outputLen
== 0) {
1381 PR_SetError(SEC_ERROR_INVALID_ARGS
, 0);
1385 auto cleanup
= MakeScopeExit([&] {
1386 GatherCertificateCompressionTelemetry(rv
, brotli
, *usedLen
, input
->len
);
1389 size_t uncompressedSize
= outputLen
;
1390 BrotliDecoderResult result
= BrotliDecoderDecompress(
1391 input
->len
, input
->data
, &uncompressedSize
, output
);
1393 if (result
!= BROTLI_DECODER_RESULT_SUCCESS
) {
1394 PR_SetError(SEC_ERROR_BAD_DATA
, 0);
1398 *usedLen
= uncompressedSize
;
1403 SECStatus
zstdCertificateDecode(const SECItem
* input
, unsigned char* output
,
1404 size_t outputLen
, size_t* usedLen
) {
1405 SECStatus rv
= SECFailure
;
1407 if (!input
|| !input
->data
|| input
->len
== 0 || !output
|| outputLen
== 0) {
1408 PR_SetError(SEC_ERROR_INVALID_ARGS
, 0);
1412 auto cleanup
= MakeScopeExit([&] {
1413 GatherCertificateCompressionTelemetry(rv
, zstd
, *usedLen
, input
->len
);
1416 size_t result
= ZSTD_decompress(output
, outputLen
, input
->data
, input
->len
);
1418 if (ZSTD_isError(result
)) {
1419 PR_SetError(SEC_ERROR_BAD_DATA
, 0);
1428 static nsresult
nsSSLIOLayerSetOptions(PRFileDesc
* fd
, bool forSTARTTLS
,
1429 bool haveProxy
, const char* host
,
1431 NSSSocketControl
* infoObject
) {
1432 if (forSTARTTLS
|| haveProxy
) {
1433 if (SECSuccess
!= SSL_OptionSet(fd
, SSL_SECURITY
, false)) {
1434 return NS_ERROR_FAILURE
;
1438 SSLVersionRange range
;
1439 if (SSL_VersionRangeGet(fd
, &range
) != SECSuccess
) {
1440 return NS_ERROR_FAILURE
;
1443 // Set TLS 1.3 compat mode.
1444 if (SECSuccess
!= SSL_OptionSet(fd
, SSL_ENABLE_TLS13_COMPAT_MODE
, PR_TRUE
)) {
1445 MOZ_LOG(gPIPNSSLog
, LogLevel::Error
,
1446 ("[%p] nsSSLIOLayerSetOptions: Setting compat mode failed\n", fd
));
1449 // setting TLS max version
1450 uint32_t versionFlags
=
1451 getTLSProviderFlagMaxVersion(infoObject
->GetProviderTlsFlags());
1454 gPIPNSSLog
, LogLevel::Debug
,
1455 ("[%p] nsSSLIOLayerSetOptions: version flags %d\n", fd
, versionFlags
));
1456 if (versionFlags
== kTLSProviderFlagMaxVersion10
) {
1457 range
.max
= SSL_LIBRARY_VERSION_TLS_1_0
;
1458 } else if (versionFlags
== kTLSProviderFlagMaxVersion11
) {
1459 range
.max
= SSL_LIBRARY_VERSION_TLS_1_1
;
1460 } else if (versionFlags
== kTLSProviderFlagMaxVersion12
) {
1461 range
.max
= SSL_LIBRARY_VERSION_TLS_1_2
;
1462 } else if (versionFlags
== kTLSProviderFlagMaxVersion13
) {
1463 range
.max
= SSL_LIBRARY_VERSION_TLS_1_3
;
1465 MOZ_LOG(gPIPNSSLog
, LogLevel::Error
,
1466 ("[%p] nsSSLIOLayerSetOptions: unknown version flags %d\n", fd
,
1471 if ((infoObject
->GetProviderFlags() & nsISocketProvider::BE_CONSERVATIVE
) &&
1472 (range
.max
> SSL_LIBRARY_VERSION_TLS_1_2
)) {
1473 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1474 ("[%p] nsSSLIOLayerSetOptions: range.max limited to 1.2 due to "
1475 "BE_CONSERVATIVE flag\n",
1477 range
.max
= SSL_LIBRARY_VERSION_TLS_1_2
;
1480 uint16_t maxEnabledVersion
= range
.max
;
1481 infoObject
->AdjustForTLSIntolerance(range
);
1483 gPIPNSSLog
, LogLevel::Debug
,
1484 ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)\n",
1485 fd
, static_cast<unsigned int>(range
.min
),
1486 static_cast<unsigned int>(range
.max
)));
1488 // If the user has set their minimum version to something higher than what
1489 // we've now set the maximum to, this will result in an inconsistent version
1490 // range unless we fix it up. This will override their preference, but we only
1491 // do this for sites critical to the operation of the browser (e.g. update
1492 // servers) and telemetry experiments.
1493 if (range
.min
> range
.max
) {
1494 range
.min
= range
.max
;
1497 if (SSL_VersionRangeSet(fd
, &range
) != SECSuccess
) {
1498 return NS_ERROR_FAILURE
;
1500 infoObject
->SetTLSVersionRange(range
);
1502 // when adjustForTLSIntolerance tweaks the maximum version downward,
1503 // we tell the server using this SCSV so they can detect a downgrade attack
1504 if (range
.max
< maxEnabledVersion
) {
1505 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1506 ("[%p] nsSSLIOLayerSetOptions: enabling TLS_FALLBACK_SCSV\n", fd
));
1507 // Some servers will choke if we send the fallback SCSV with TLS 1.2.
1508 if (range
.max
< SSL_LIBRARY_VERSION_TLS_1_2
) {
1509 if (SECSuccess
!= SSL_OptionSet(fd
, SSL_ENABLE_FALLBACK_SCSV
, true)) {
1510 return NS_ERROR_FAILURE
;
1513 // tell NSS the max enabled version to make anti-downgrade effective
1514 if (SECSuccess
!= SSL_SetDowngradeCheckVersion(fd
, maxEnabledVersion
)) {
1515 return NS_ERROR_FAILURE
;
1519 // Enable ECH GREASE if suitable. Has no impact if 'real' ECH is being used.
1520 if (range
.max
>= SSL_LIBRARY_VERSION_TLS_1_3
&&
1521 !(infoObject
->GetProviderFlags() & (nsISocketProvider::BE_CONSERVATIVE
|
1522 nsISocketProvider::DONT_TRY_ECH
)) &&
1523 StaticPrefs::security_tls_ech_grease_probability()) {
1524 if ((RandomUint64().valueOr(0) % 100) >=
1525 100 - StaticPrefs::security_tls_ech_grease_probability()) {
1526 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
,
1527 ("[%p] nsSSLIOLayerSetOptions: enabling TLS ECH Grease\n", fd
));
1528 if (SECSuccess
!= SSL_EnableTls13GreaseEch(fd
, PR_TRUE
)) {
1529 return NS_ERROR_FAILURE
;
1531 // ECH Padding can be between 1 and 255
1533 SSL_SetTls13GreaseEchSize(
1534 fd
, std::clamp(StaticPrefs::security_tls_ech_grease_size(), 1U,
1536 return NS_ERROR_FAILURE
;
1538 infoObject
->UpdateEchExtensionStatus(EchExtensionStatus::kGREASE
);
1542 // Include a modest set of named groups in supported_groups and determine how
1543 // many key shares to send. Please change getKeaGroupName in
1544 // nsNSSCallbacks.cpp when changing the lists here.
1545 unsigned int additional_shares
=
1546 StaticPrefs::security_tls_client_hello_send_p256_keyshare();
1547 if (StaticPrefs::security_tls_enable_kyber() &&
1548 range
.max
>= SSL_LIBRARY_VERSION_TLS_1_3
&&
1549 !(infoObject
->GetProviderFlags() &
1550 (nsISocketProvider::BE_CONSERVATIVE
| nsISocketProvider::IS_RETRY
))) {
1551 const SSLNamedGroup namedGroups
[] = {
1552 ssl_grp_kem_mlkem768x25519
, ssl_grp_ec_curve25519
, ssl_grp_ec_secp256r1
,
1553 ssl_grp_ec_secp384r1
, ssl_grp_ec_secp521r1
, ssl_grp_ffdhe_2048
,
1554 ssl_grp_ffdhe_3072
};
1556 SSL_NamedGroupConfig(fd
, namedGroups
, std::size(namedGroups
))) {
1557 return NS_ERROR_FAILURE
;
1559 additional_shares
+= 1;
1560 infoObject
->WillSendMlkemShare();
1562 const SSLNamedGroup namedGroups
[] = {
1563 ssl_grp_ec_curve25519
, ssl_grp_ec_secp256r1
, ssl_grp_ec_secp384r1
,
1564 ssl_grp_ec_secp521r1
, ssl_grp_ffdhe_2048
, ssl_grp_ffdhe_3072
};
1565 // Skip the |ssl_grp_kem_mlkem768x25519| entry.
1567 SSL_NamedGroupConfig(fd
, namedGroups
, std::size(namedGroups
))) {
1568 return NS_ERROR_FAILURE
;
1572 // If additional_shares == 2, send mlkem768x25519, x25519, and p256.
1573 // If additional_shares == 1, send {mlkem768x25519, x25519} or {x25519, p256}.
1574 // If additional_shares == 0, send x25519.
1575 if (SECSuccess
!= SSL_SendAdditionalKeyShares(fd
, additional_shares
)) {
1576 return NS_ERROR_FAILURE
;
1579 // Enabling Certificate Compression Decoding mechanisms.
1580 if (range
.max
>= SSL_LIBRARY_VERSION_TLS_1_3
&&
1581 !(infoObject
->GetProviderFlags() &
1582 (nsISocketProvider::BE_CONSERVATIVE
| nsISocketProvider::IS_RETRY
))) {
1583 SSLCertificateCompressionAlgorithm zlibAlg
= {1, "zlib", nullptr,
1584 zlibCertificateDecode
};
1586 SSLCertificateCompressionAlgorithm brotliAlg
= {2, "brotli", nullptr,
1587 brotliCertificateDecode
};
1589 SSLCertificateCompressionAlgorithm zstdAlg
= {3, "zstd", nullptr,
1590 zstdCertificateDecode
};
1592 if (StaticPrefs::security_tls_enable_certificate_compression_zlib() &&
1593 SSL_SetCertificateCompressionAlgorithm(fd
, zlibAlg
) != SECSuccess
) {
1594 return NS_ERROR_FAILURE
;
1597 if (StaticPrefs::security_tls_enable_certificate_compression_brotli() &&
1598 SSL_SetCertificateCompressionAlgorithm(fd
, brotliAlg
) != SECSuccess
) {
1599 return NS_ERROR_FAILURE
;
1602 if (StaticPrefs::security_tls_enable_certificate_compression_zstd() &&
1603 SSL_SetCertificateCompressionAlgorithm(fd
, zstdAlg
) != SECSuccess
) {
1604 return NS_ERROR_FAILURE
;
1608 // NOTE: Should this list ever include ssl_sig_rsa_pss_pss_sha* (or should
1609 // it become possible to enable this scheme via a pref), it is required
1610 // to test that a Delegated Credential containing a small-modulus RSA-PSS SPKI
1611 // is properly rejected. NSS will not advertise PKCS1 or RSAE schemes (which
1612 // the |ssl_sig_rsa_pss_*| defines alias, meaning we will not currently accept
1615 SSL_SignatureSchemePrefSet(fd
, sEnabledSignatureSchemes
,
1616 std::size(sEnabledSignatureSchemes
))) {
1617 return NS_ERROR_FAILURE
;
1620 bool enabled
= StaticPrefs::security_ssl_enable_ocsp_stapling();
1621 if (SECSuccess
!= SSL_OptionSet(fd
, SSL_ENABLE_OCSP_STAPLING
, enabled
)) {
1622 return NS_ERROR_FAILURE
;
1625 bool sctsEnabled
= GetCertificateTransparencyMode() !=
1626 CertVerifier::CertificateTransparencyMode::Disabled
;
1628 SSL_OptionSet(fd
, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS
, sctsEnabled
)) {
1629 return NS_ERROR_FAILURE
;
1632 if (SECSuccess
!= SSL_OptionSet(fd
, SSL_HANDSHAKE_AS_CLIENT
, true)) {
1633 return NS_ERROR_FAILURE
;
1636 #if defined(__arm__)
1637 if (!mozilla::supports_arm_aes()) {
1638 unsigned int enabledCiphers
= 0;
1639 std::vector
<uint16_t> ciphers(SSL_GetNumImplementedCiphers());
1641 // Returns only the enabled (reflecting prefs) ciphers, ordered
1642 // by their occurence in
1643 // https://hg.mozilla.org/projects/nss/file/a75ea4cdacd95282c6c245ebb849c25e84ccd908/lib/ssl/ssl3con.c#l87
1644 if (SSL_CipherSuiteOrderGet(fd
, ciphers
.data(), &enabledCiphers
) !=
1646 return NS_ERROR_FAILURE
;
1649 // On ARM, prefer (TLS_CHACHA20_POLY1305_SHA256) over AES when hardware
1650 // support for AES isn't available. However, it may be disabled. If enabled,
1651 // it will either be element [0] or [1]*. If [0], we're done. If [1], swap
1652 // it with [0] (TLS_AES_128_GCM_SHA256).
1653 // *(assuming the compile-time order remains unchanged)
1654 if (enabledCiphers
> 1) {
1655 if (ciphers
[0] != TLS_CHACHA20_POLY1305_SHA256
&&
1656 ciphers
[1] == TLS_CHACHA20_POLY1305_SHA256
) {
1657 std::swap(ciphers
[0], ciphers
[1]);
1659 if (SSL_CipherSuiteOrderSet(fd
, ciphers
.data(), enabledCiphers
) !=
1661 return NS_ERROR_FAILURE
;
1668 // Set the Peer ID so that SSL proxy connections work properly and to
1669 // separate anonymous and/or private browsing connections.
1670 nsAutoCString peerId
;
1671 infoObject
->GetPeerId(peerId
);
1672 if (SECSuccess
!= SSL_SetSockPeerID(fd
, peerId
.get())) {
1673 return NS_ERROR_FAILURE
;
1676 uint32_t flags
= infoObject
->GetProviderFlags();
1677 if (flags
& nsISocketProvider::NO_PERMANENT_STORAGE
) {
1678 if (SECSuccess
!= SSL_OptionSet(fd
, SSL_ENABLE_SESSION_TICKETS
, false) ||
1679 SECSuccess
!= SSL_OptionSet(fd
, SSL_NO_CACHE
, true)) {
1680 return NS_ERROR_FAILURE
;
1687 SECStatus
StoreResumptionToken(PRFileDesc
* fd
, const PRUint8
* resumptionToken
,
1688 unsigned int len
, void* ctx
) {
1690 if (SSL_OptionGet(fd
, SSL_ENABLE_SESSION_TICKETS
, &val
) != SECSuccess
||
1695 NSSSocketControl
* infoObject
= (NSSSocketControl
*)ctx
;
1700 nsAutoCString peerId
;
1701 infoObject
->GetPeerId(peerId
);
1703 net::SSLTokensCache::Put(peerId
, resumptionToken
, len
, infoObject
))) {
1710 nsresult
nsSSLIOLayerAddToSocket(int32_t family
, const char* host
, int32_t port
,
1711 nsIProxyInfo
* proxy
,
1712 const OriginAttributes
& originAttributes
,
1714 nsITLSSocketControl
** tlsSocketControl
,
1715 bool forSTARTTLS
, uint32_t providerFlags
,
1716 uint32_t providerTlsFlags
) {
1717 RefPtr
<nsSSLIOLayerHelpers
> sslIOLayerHelpers
;
1718 if (providerTlsFlags
) {
1720 new nsSSLIOLayerHelpers(PublicOrPrivate::Public
, providerTlsFlags
);
1721 sslIOLayerHelpers
->Init();
1723 bool isPrivate
= providerFlags
& nsISocketProvider::NO_PERMANENT_STORAGE
||
1724 originAttributes
.IsPrivateBrowsing();
1726 isPrivate
? PrivateSSLIOLayerHelpers() : PublicSSLIOLayerHelpers();
1729 RefPtr
<NSSSocketControl
> infoObject(new NSSSocketControl(
1730 nsDependentCString(host
), port
, sslIOLayerHelpers
.forget(), providerFlags
,
1733 return NS_ERROR_FAILURE
;
1736 infoObject
->SetForSTARTTLS(forSTARTTLS
);
1737 infoObject
->SetOriginAttributes(originAttributes
);
1739 bool haveProxy
= false;
1740 bool haveHTTPSProxy
= false;
1742 nsAutoCString proxyHost
;
1743 nsresult rv
= proxy
->GetHost(proxyHost
);
1744 if (NS_FAILED(rv
)) {
1747 haveProxy
= !proxyHost
.IsEmpty();
1749 haveHTTPSProxy
= haveProxy
&& NS_SUCCEEDED(proxy
->GetType(type
)) &&
1750 type
.EqualsLiteral("https");
1753 // A plaintext observer shim is inserted so we can observe some protocol
1754 // details without modifying nss
1755 PRFileDesc
* plaintextLayer
=
1756 PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity
,
1757 &nsSSLIOLayerHelpers::nsSSLPlaintextLayerMethods
);
1758 if (!plaintextLayer
) {
1759 return NS_ERROR_FAILURE
;
1761 plaintextLayer
->secret
= (PRFilePrivate
*)infoObject
.get();
1762 if (PR_PushIOLayer(fd
, PR_TOP_IO_LAYER
, plaintextLayer
) != PR_SUCCESS
) {
1763 plaintextLayer
->dtor(plaintextLayer
);
1764 return NS_ERROR_FAILURE
;
1766 auto plaintextLayerCleanup
= MakeScopeExit([&fd
] {
1767 // Note that PR_*IOLayer operations may modify the stack of fds, so a
1768 // previously-valid pointer may no longer point to what we think it points
1769 // to after calling PR_PopIOLayer. We must operate on the pointer returned
1770 // by PR_PopIOLayer.
1771 PRFileDesc
* plaintextLayer
=
1772 PR_PopIOLayer(fd
, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity
);
1773 if (plaintextLayer
) {
1774 plaintextLayer
->dtor(plaintextLayer
);
1778 PRFileDesc
* sslSock
=
1779 nsSSLIOLayerImportFD(fd
, infoObject
, host
, haveHTTPSProxy
);
1781 return NS_ERROR_FAILURE
;
1784 nsresult rv
= nsSSLIOLayerSetOptions(sslSock
, forSTARTTLS
, haveProxy
, host
,
1786 if (NS_FAILED(rv
)) {
1790 // Now, layer ourselves on top of the SSL socket...
1792 PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity
,
1793 &nsSSLIOLayerHelpers::nsSSLIOLayerMethods
);
1795 return NS_ERROR_FAILURE
;
1797 // Give the layer an owning reference to the NSSSocketControl.
1798 // This is the simplest way to prevent the layer from outliving the
1799 // NSSSocketControl (otherwise, the layer could potentially use it in
1800 // nsSSLIOLayerClose after it has been released).
1801 // nsSSLIOLayerClose takes the owning reference when the underlying fd gets
1802 // closed. If the fd never gets closed (as in, leaks), the NSSSocketControl
1804 layer
->secret
= (PRFilePrivate
*)do_AddRef(infoObject
).take();
1806 if (PR_PushIOLayer(sslSock
, PR_GetLayersIdentity(sslSock
), layer
) !=
1809 return NS_ERROR_FAILURE
;
1811 auto layerCleanup
= MakeScopeExit([&fd
] {
1813 PR_PopIOLayer(fd
, nsSSLIOLayerHelpers::nsSSLIOLayerIdentity
);
1819 // We are going use a clear connection first //
1820 if (forSTARTTLS
|| haveProxy
) {
1821 infoObject
->SetHandshakeNotPending();
1824 rv
= infoObject
->SetResumptionTokenFromExternalCache(sslSock
);
1825 if (NS_FAILED(rv
)) {
1828 if (SSL_SetResumptionTokenCallback(sslSock
, &StoreResumptionToken
,
1829 infoObject
) != SECSuccess
) {
1830 return NS_ERROR_FAILURE
;
1833 MOZ_LOG(gPIPNSSLog
, LogLevel::Debug
, ("[%p] Socket set up", (void*)sslSock
));
1835 (void)infoObject
->SetFileDescPtr(sslSock
);
1836 layerCleanup
.release();
1837 plaintextLayerCleanup
.release();
1838 *tlsSocketControl
= infoObject
.forget().take();
1844 const uint8_t kIPCClientCertsObjectTypeCert
= 1;
1845 const uint8_t kIPCClientCertsObjectTypeRSAKey
= 2;
1846 const uint8_t kIPCClientCertsObjectTypeECKey
= 3;
1848 // This function is provided to the IPC client certs module so it can cause the
1849 // parent process to find certificates and keys and send identifying
1850 // information about them over IPC.
1851 void DoFindObjects(FindObjectsCallback cb
, void* ctx
) {
1852 net::SocketProcessChild
* socketChild
=
1853 net::SocketProcessChild::GetSingleton();
1858 RefPtr
<IPCClientCertsChild
> ipcClientCertsActor(
1859 socketChild
->GetIPCClientCertsActor());
1860 if (!ipcClientCertsActor
) {
1863 nsTArray
<IPCClientCertObject
> objects
;
1864 if (!ipcClientCertsActor
->SendFindObjects(&objects
)) {
1867 for (const auto& object
: objects
) {
1868 switch (object
.type()) {
1869 case IPCClientCertObject::TECKey
:
1870 cb(kIPCClientCertsObjectTypeECKey
, object
.get_ECKey().params().Length(),
1871 object
.get_ECKey().params().Elements(),
1872 object
.get_ECKey().cert().Length(),
1873 object
.get_ECKey().cert().Elements(), object
.get_ECKey().slotType(),
1876 case IPCClientCertObject::TRSAKey
:
1877 cb(kIPCClientCertsObjectTypeRSAKey
,
1878 object
.get_RSAKey().modulus().Length(),
1879 object
.get_RSAKey().modulus().Elements(),
1880 object
.get_RSAKey().cert().Length(),
1881 object
.get_RSAKey().cert().Elements(),
1882 object
.get_RSAKey().slotType(), ctx
);
1884 case IPCClientCertObject::TCertificate
:
1885 cb(kIPCClientCertsObjectTypeCert
,
1886 object
.get_Certificate().der().Length(),
1887 object
.get_Certificate().der().Elements(), 0, nullptr,
1888 object
.get_Certificate().slotType(), ctx
);
1891 MOZ_ASSERT_UNREACHABLE("unhandled IPCClientCertObject type");
1897 // This function is provided to the IPC client certs module so it can cause the
1898 // parent process to sign the given data using the key corresponding to the
1899 // given certificate, using the given parameters.
1900 void DoSign(size_t cert_len
, const uint8_t* cert
, size_t data_len
,
1901 const uint8_t* data
, size_t params_len
, const uint8_t* params
,
1902 SignCallback cb
, void* ctx
) {
1903 net::SocketProcessChild
* socketChild
=
1904 net::SocketProcessChild::GetSingleton();
1909 RefPtr
<IPCClientCertsChild
> ipcClientCertsActor(
1910 socketChild
->GetIPCClientCertsActor());
1911 if (!ipcClientCertsActor
) {
1914 ByteArray
certBytes(nsTArray
<uint8_t>(cert
, cert_len
));
1915 ByteArray
dataBytes(nsTArray
<uint8_t>(data
, data_len
));
1916 ByteArray
paramsBytes(nsTArray
<uint8_t>(params
, params_len
));
1917 ByteArray signature
;
1918 if (!ipcClientCertsActor
->SendSign(certBytes
, dataBytes
, paramsBytes
,
1922 cb(signature
.data().Length(), signature
.data().Elements(), ctx
);