Bug 1935611 - Fix libyuv/libpng link failed for loongarch64. r=glandium,tnikkel,ng
[gecko.git] / security / manager / ssl / nsNSSIOLayer.cpp
blob20732880718acb275cf5b47540d257e9d86c3a4d
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"
9 #include <algorithm>
10 #include <utility>
11 #include <vector>
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"
20 #include "keyhi.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"
37 #include "nsArray.h"
38 #include "nsArrayUtils.h"
39 #include "nsCRT.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"
49 #include "prmem.h"
50 #include "prnetdb.h"
51 #include "secder.h"
52 #include "secerr.h"
53 #include "ssl.h"
54 #include "sslerr.h"
55 #include "sslexp.h"
56 #include "sslproto.h"
57 #include "zlib.h"
58 #include "brotli/decode.h"
59 #include "zstd/zstd.h"
61 #if defined(__arm__)
62 # include "mozilla/arm.h"
63 #endif
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
77 // file.
79 namespace {
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.
98 enum {
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) {
115 key = hostName;
116 key.AppendLiteral(":");
117 key.AppendInt(port);
120 } // unnamed namespace
122 extern LazyLogModule gPIPNSSLog;
124 namespace {
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);
136 return nullptr;
139 NSSSocketControl* socketInfo = (NSSSocketControl*)fd->secret;
141 if (socketInfo->IsCanceled()) {
142 PRErrorCode err = socketInfo->GetErrorCode();
143 PR_SetError(err, 0);
144 if (op == reading || op == writing) {
145 // We must do TLS intolerance checks for reads and writes, for timeouts
146 // in particular.
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.
152 return nullptr;
155 return socketInfo;
158 } // namespace
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()));
170 return status;
173 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("[%p] Connect\n", (void*)fd));
174 return status;
177 void nsSSLIOLayerHelpers::rememberTolerantAtVersion(const nsACString& hostName,
178 uint16_t port,
179 uint16_t tolerant) {
180 nsCString key;
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
193 } else {
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,
205 uint16_t port) {
206 nsCString key;
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);
238 return false;
241 nsCString key;
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.
251 return false;
253 if ((entry.intolerant != 0 && intolerant >= entry.intolerant)) {
254 // We already know that the server is intolerant at a lower version.
255 return true;
257 } else {
258 entry.tolerant = 0;
261 entry.intolerant = intolerant;
262 entry.intoleranceReason = intoleranceReason;
263 entry.AssertInvariant();
264 mTLSIntoleranceInfo.InsertOrUpdate(key, entry);
266 return true;
269 void nsSSLIOLayerHelpers::adjustForTLSIntolerance(
270 const nsACString& hostName, uint16_t port,
271 /*in/out*/ SSLVersionRange& range) {
272 IntoleranceEntry entry;
275 nsCString key;
276 getSiteKey(hostName, port, key);
278 MutexAutoLock lock(mutex);
279 if (!mTLSIntoleranceInfo.Get(key, &entry)) {
280 return;
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;
300 nsCString key;
301 getSiteKey(hostName, port, key);
303 MutexAutoLock lock(mutex);
304 if (!mTLSIntoleranceInfo.Get(key, &entry)) {
305 return 0;
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) {
320 if (!fd) {
321 return PR_FAILURE;
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;
331 if (!socketInfo) {
332 return PR_FAILURE;
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";
346 int i = 0;
347 int l = 0;
348 char ch;
349 char* c;
350 char* h;
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);
356 h = hexbuf;
357 c = chrbuf;
359 while (i < len) {
360 ch = buf[i];
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);
366 h = hexbuf;
367 c = chrbuf;
368 l = 0;
371 // Convert a character to hex.
372 *h++ = hex[(ch >> 4) & 0xf];
373 *h++ = hex[ch & 0xf];
374 h++;
376 // Put the character (if it's printable) into the character buffer.
377 if ((ch >= 0x20) && (ch <= 0x7e)) {
378 *c++ = ch;
379 } else {
380 *c++ = '.';
382 i++;
383 l++;
385 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("%s%s\n", hexbuf, chrbuf));
388 # define DEBUG_DUMP_BUFFER(buf, len) nsDumpBuffer(buf, len)
389 #else
390 # define DEBUG_DUMP_BUFFER(buf, len)
391 #endif
393 namespace {
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
399 switch (err) {
400 case SSL_ERROR_BAD_MAC_ALERT:
401 return 1;
402 case SSL_ERROR_BAD_MAC_READ:
403 return 2;
404 case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
405 return 3;
406 case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
407 return 4;
408 case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
409 return 6;
410 case SSL_ERROR_NO_CYPHER_OVERLAP:
411 return 7;
412 case SSL_ERROR_UNSUPPORTED_VERSION:
413 return 10;
414 case SSL_ERROR_PROTOCOL_VERSION_ALERT:
415 return 11;
416 case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
417 return 13;
418 case SSL_ERROR_DECODE_ERROR_ALERT:
419 return 14;
420 case PR_CONNECT_RESET_ERROR:
421 return 16;
422 case PR_END_OF_FILE_ERROR:
423 return 17;
424 case SSL_ERROR_INTERNAL_ERROR_ALERT:
425 return 18;
426 default:
427 return 0;
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.
439 return true;
442 if (!socketInfo->IsPreliminaryHandshakeDone() &&
443 !socketInfo->HasTls13HandshakeSecrets() && socketInfo->SentMlkemShare()) {
444 nsAutoCString errorName;
445 const char* prErrorName = PR_ErrorToName(err);
446 if (prErrorName) {
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
451 // retry.
452 return true;
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();
480 return false;
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
487 // EOF.
488 if ((err == PR_CONNECT_RESET_ERROR || err == PR_END_OF_FILE_ERROR) &&
489 socketInfo->GetForSTARTTLS()) {
490 return false;
493 uint32_t reason = tlsIntoleranceTelemetryBucket(err);
494 if (reason == 0) {
495 return false;
498 Telemetry::HistogramID pre;
499 Telemetry::HistogramID post;
500 switch (range.max) {
501 case SSL_LIBRARY_VERSION_TLS_1_3:
502 pre = Telemetry::SSL_TLS13_INTOLERANCE_REASON_PRE;
503 post = Telemetry::SSL_TLS13_INTOLERANCE_REASON_POST;
504 break;
505 case SSL_LIBRARY_VERSION_TLS_1_2:
506 pre = Telemetry::SSL_TLS12_INTOLERANCE_REASON_PRE;
507 post = Telemetry::SSL_TLS12_INTOLERANCE_REASON_POST;
508 break;
509 case SSL_LIBRARY_VERSION_TLS_1_1:
510 pre = Telemetry::SSL_TLS11_INTOLERANCE_REASON_PRE;
511 post = Telemetry::SSL_TLS11_INTOLERANCE_REASON_POST;
512 break;
513 case SSL_LIBRARY_VERSION_TLS_1_0:
514 pre = Telemetry::SSL_TLS10_INTOLERANCE_REASON_PRE;
515 post = Telemetry::SSL_TLS10_INTOLERANCE_REASON_POST;
516 break;
517 default:
518 MOZ_CRASH("impossible TLS version");
519 return false;
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)) {
527 return false;
530 Telemetry::Accumulate(post, reason);
532 return true;
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,
546 PRErrorCode err,
547 NSSSocketControl* socketInfo) {
548 uint32_t bucket;
550 // A negative bytesTransferred or a 0 read are errors.
551 if (bytesTransferred > 0) {
552 bucket = 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.
556 MOZ_ASSERT(false);
557 bucket = 671;
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;
568 } else {
569 bucket = 671;
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);
584 break;
585 case EchExtensionStatus::kReal:
586 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT_ECH, bucket);
587 break;
588 default:
589 break;
591 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_RESULT, bucket);
593 if (bucket == 0) {
594 nsCOMPtr<nsITransportSecurityInfo> securityInfo;
595 if (NS_FAILED(socketInfo->GetSecurityInfo(getter_AddRefs(securityInfo))) ||
596 !securityInfo) {
597 return;
599 // Web Privacy Telemetry for successful connections.
600 bool success = true;
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.
618 if (success) {
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
667 // happen.
668 reportHandshakeResult(bytesTransferred, wasReading, originalError,
669 socketInfo);
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) {
684 if (wasReading) {
685 errorToUse = PR_END_OF_FILE_ERROR;
686 } else {
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);
697 if (wantRetry) {
698 MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
699 ("[%p] checkHandshake: will retry with lower max TLS version",
700 ssl_layer_fd));
701 // Setting the error PR_CONNECT_RESET_ERROR causes necko to retry the
702 // connection.
703 PR_SetError(PR_CONNECT_RESET_ERROR, 0);
704 } else {
705 PR_SetError(originalError, 0);
708 return bytesTransferred;
711 } // namespace
713 static int16_t nsSSLIOLayerPoll(PRFileDesc* fd, int16_t in_flags,
714 int16_t* out_flags) {
715 if (!out_flags) {
716 NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
717 return 0;
720 *out_flags = 0;
722 NSSSocketControl* socketInfo =
723 getSocketInfoIfRunning(fd, not_reading_or_writing);
725 if (!socketInfo) {
726 // If we get here, it is probably because certificate validation failed
727 // and this is the first I/O operation after the failure.
728 MOZ_LOG(
729 gPIPNSSLog, LogLevel::Debug,
730 ("[%p] polling SSL socket right after certificate verification failed "
731 "or NSS shutdown or SDR logout %d\n",
732 fd, (int)in_flags));
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
740 return in_flags;
743 MOZ_LOG(gPIPNSSLog, LogLevel::Verbose,
744 (socketInfo->IsWaitingForCertVerification()
745 ? "[%p] polling SSL socket during certificate verification "
746 "using lower %d\n"
747 : "[%p] poll SSL socket using lower %d\n",
748 fd, (int)in_flags));
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));
759 return result;
762 nsSSLIOLayerHelpers::nsSSLIOLayerHelpers(PublicOrPrivate aPublicOrPrivate,
763 uint32_t aTlsFlags)
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);
773 return -1;
776 static int64_t PSMAvailable64(PRFileDesc*) {
777 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
778 return -1;
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);
813 return -1;
816 int32_t bytesRead =
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);
824 #endif
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;
834 if (flags != 0) {
835 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
836 return -1;
839 #ifdef DEBUG_SSL_VERBOSE
840 DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
841 #endif
843 if (socketInfo->IsShortWritePending() && amount > 0) {
844 // We got "SSL short write" last time, try to flush the pending byte.
845 #ifdef DEBUG
846 socketInfo->CheckShortWrittenBuffer(static_cast<const unsigned char*>(buf),
847 amount);
848 #endif
850 buf = socketInfo->GetShortWritePendingByteRef();
851 amount = 1;
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));
887 MOZ_LOG(
888 gPIPNSSLog, LogLevel::Verbose,
889 ("[%p] indicated SSL short write for %d bytes (written just %d bytes)",
890 fd, amount, bytesWritten));
892 bytesWritten = -1;
893 PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
895 #ifdef DEBUG
896 socketInfo->RememberShortWrittenBuffer(
897 static_cast<const unsigned char*>(buf));
898 #endif
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,
927 int32_t amount) {
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)) {
933 return PR_FAILURE;
936 return fd->lower->methods->connectcontinue(fd, out_flags);
939 NS_IMPL_ISUPPORTS(nsSSLIOLayerHelpers, nsIObserver)
941 NS_IMETHODIMP
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) {
953 clearStoredData();
955 return NS_OK;
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();
966 /*static*/
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;
991 int32_t bytesRead =
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);
1000 return 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,
1034 PRIntervalTime>;
1035 nsSSLIOLayerMethods.accept =
1036 InvalidPRIOMethod<PRFileDesc*, nullptr, PRFileDesc*, PRNetAddr*,
1037 PRIntervalTime>;
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");
1087 if (isPublic()) {
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");
1092 } else {
1093 nsCOMPtr<nsIObserverService> obsSvc =
1094 mozilla::services::GetObserverService();
1095 if (obsSvc) {
1096 obsSvc->AddObserver(this, "last-pb-context-exited", false);
1099 } else {
1100 MOZ_ASSERT(mTlsFlags, "Only per socket version can ignore prefs");
1103 return NS_OK;
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 {
1163 public:
1164 explicit FallbackPrefRemover(const nsACString& aHost)
1165 : mozilla::Runnable("FallbackPrefRemover"), mHost(aHost) {}
1166 NS_IMETHOD Run() override;
1168 private:
1169 nsCString mHost;
1172 NS_IMETHODIMP
1173 FallbackPrefRemover::Run() {
1174 MOZ_ASSERT(NS_IsMainThread());
1175 nsAutoCString oldValue;
1176 Preferences::GetCString("security.tls.insecure_fallback_hosts", oldValue);
1177 nsCString newValue;
1178 for (const nsACString& host :
1179 nsCCharSeparatedTokenizer(oldValue, ',').ToRange()) {
1180 if (host.Equals(mHost)) {
1181 continue;
1183 if (!newValue.IsEmpty()) {
1184 newValue.Append(',');
1186 newValue.Append(host);
1188 Preferences::SetCString("security.tls.insecure_fallback_hosts", newValue);
1189 return NS_OK;
1192 void nsSSLIOLayerHelpers::removeInsecureFallbackSite(const nsACString& hostname,
1193 uint16_t port) {
1194 forgetIntolerance(hostname, port);
1196 MutexAutoLock lock(mutex);
1197 if (!mInsecureFallbackSites.Contains(hostname)) {
1198 return;
1200 mInsecureFallbackSites.RemoveEntry(hostname);
1202 if (!isPublic()) {
1203 return;
1205 RefPtr<Runnable> runnable = new FallbackPrefRemover(hostname);
1206 if (NS_IsMainThread()) {
1207 runnable->Run();
1208 } else {
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,
1221 PRFileDesc** fd,
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;
1228 nsresult rv =
1229 nsSSLIOLayerAddToSocket(family, host, port, proxy, originAttributes, sock,
1230 tlsSocketControl, forSTARTTLS, flags, tlsFlags);
1231 if (NS_FAILED(rv)) {
1232 PR_Close(sock);
1233 return rv;
1236 *fd = sock;
1237 return NS_OK;
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);
1246 if (!sslSock) {
1247 return nullptr;
1249 if (SSL_SetPKCS11PinArg(sslSock, infoObject) != SECSuccess) {
1250 return nullptr;
1252 if (SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject) !=
1253 SECSuccess) {
1254 return nullptr;
1256 if (SSL_SecretCallback(sslSock, SecretCallback, infoObject) != SECSuccess) {
1257 return nullptr;
1259 if (SSL_SetCanFalseStartCallback(sslSock, CanFalseStartCallback,
1260 infoObject) != SECSuccess) {
1261 return nullptr;
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) !=
1273 SECSuccess) {
1274 return nullptr;
1277 if (SSL_AuthCertificateHook(sslSock, AuthCertificateHook, infoObject) !=
1278 SECSuccess) {
1279 return nullptr;
1281 if (SSL_SetURL(sslSock, host) != SECSuccess) {
1282 return nullptr;
1285 return sslSock;
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)
1301 ssl_sig_ecdsa_sha1,
1302 #endif
1303 ssl_sig_rsa_pkcs1_sha1,
1306 enum CertificateCompressionAlgorithms {
1307 zlib = 0x01,
1308 brotli = 0x02,
1309 zstd = 0x03
1312 void GatherCertificateCompressionTelemetry(SECStatus rv,
1313 CertificateCompressionAlgorithms alg,
1314 PRUint64 actualCertLen,
1315 PRUint64 encodedCertLen) {
1316 nsAutoCString decoder;
1318 switch (alg) {
1319 case zlib:
1320 decoder.AssignLiteral("zlib");
1321 break;
1322 case brotli:
1323 decoder.AssignLiteral("brotli");
1324 break;
1325 case zstd:
1326 decoder.AssignLiteral("zstd");
1327 break;
1330 if (rv != SECSuccess) {
1331 mozilla::glean::cert_compression::failures.Get(decoder).Add(1);
1332 return;
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);
1343 return rv;
1346 z_stream strm = {};
1348 if (inflateInit(&strm) != Z_OK) {
1349 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
1350 return rv;
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;
1366 if (!ok) {
1367 PR_SetError(SEC_ERROR_BAD_DATA, 0);
1368 return rv;
1371 *usedLen = strm.total_out;
1372 rv = SECSuccess;
1373 return rv;
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);
1382 return rv;
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);
1395 return rv;
1398 *usedLen = uncompressedSize;
1399 rv = SECSuccess;
1400 return rv;
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);
1409 return rv;
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);
1420 return rv;
1423 *usedLen = result;
1424 rv = SECSuccess;
1425 return rv;
1428 static nsresult nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS,
1429 bool haveProxy, const char* host,
1430 int32_t port,
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());
1452 if (versionFlags) {
1453 MOZ_LOG(
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;
1464 } else {
1465 MOZ_LOG(gPIPNSSLog, LogLevel::Error,
1466 ("[%p] nsSSLIOLayerSetOptions: unknown version flags %d\n", fd,
1467 versionFlags));
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",
1476 fd));
1477 range.max = SSL_LIBRARY_VERSION_TLS_1_2;
1480 uint16_t maxEnabledVersion = range.max;
1481 infoObject->AdjustForTLSIntolerance(range);
1482 MOZ_LOG(
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
1532 if (SECSuccess !=
1533 SSL_SetTls13GreaseEchSize(
1534 fd, std::clamp(StaticPrefs::security_tls_ech_grease_size(), 1U,
1535 255U))) {
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};
1555 if (SECSuccess !=
1556 SSL_NamedGroupConfig(fd, namedGroups, std::size(namedGroups))) {
1557 return NS_ERROR_FAILURE;
1559 additional_shares += 1;
1560 infoObject->WillSendMlkemShare();
1561 } else {
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.
1566 if (SECSuccess !=
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
1613 // any RSA DC.
1614 if (SECSuccess !=
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;
1627 if (SECSuccess !=
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) !=
1645 SECSuccess) {
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) !=
1660 SECSuccess) {
1661 return NS_ERROR_FAILURE;
1666 #endif
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;
1684 return NS_OK;
1687 SECStatus StoreResumptionToken(PRFileDesc* fd, const PRUint8* resumptionToken,
1688 unsigned int len, void* ctx) {
1689 PRIntn val;
1690 if (SSL_OptionGet(fd, SSL_ENABLE_SESSION_TICKETS, &val) != SECSuccess ||
1691 val == 0) {
1692 return SECFailure;
1695 NSSSocketControl* infoObject = (NSSSocketControl*)ctx;
1696 if (!infoObject) {
1697 return SECFailure;
1700 nsAutoCString peerId;
1701 infoObject->GetPeerId(peerId);
1702 if (NS_FAILED(
1703 net::SSLTokensCache::Put(peerId, resumptionToken, len, infoObject))) {
1704 return SECFailure;
1707 return SECSuccess;
1710 nsresult nsSSLIOLayerAddToSocket(int32_t family, const char* host, int32_t port,
1711 nsIProxyInfo* proxy,
1712 const OriginAttributes& originAttributes,
1713 PRFileDesc* fd,
1714 nsITLSSocketControl** tlsSocketControl,
1715 bool forSTARTTLS, uint32_t providerFlags,
1716 uint32_t providerTlsFlags) {
1717 RefPtr<nsSSLIOLayerHelpers> sslIOLayerHelpers;
1718 if (providerTlsFlags) {
1719 sslIOLayerHelpers =
1720 new nsSSLIOLayerHelpers(PublicOrPrivate::Public, providerTlsFlags);
1721 sslIOLayerHelpers->Init();
1722 } else {
1723 bool isPrivate = providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE ||
1724 originAttributes.IsPrivateBrowsing();
1725 sslIOLayerHelpers =
1726 isPrivate ? PrivateSSLIOLayerHelpers() : PublicSSLIOLayerHelpers();
1729 RefPtr<NSSSocketControl> infoObject(new NSSSocketControl(
1730 nsDependentCString(host), port, sslIOLayerHelpers.forget(), providerFlags,
1731 providerTlsFlags));
1732 if (!infoObject) {
1733 return NS_ERROR_FAILURE;
1736 infoObject->SetForSTARTTLS(forSTARTTLS);
1737 infoObject->SetOriginAttributes(originAttributes);
1739 bool haveProxy = false;
1740 bool haveHTTPSProxy = false;
1741 if (proxy) {
1742 nsAutoCString proxyHost;
1743 nsresult rv = proxy->GetHost(proxyHost);
1744 if (NS_FAILED(rv)) {
1745 return rv;
1747 haveProxy = !proxyHost.IsEmpty();
1748 nsAutoCString type;
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);
1780 if (!sslSock) {
1781 return NS_ERROR_FAILURE;
1784 nsresult rv = nsSSLIOLayerSetOptions(sslSock, forSTARTTLS, haveProxy, host,
1785 port, infoObject);
1786 if (NS_FAILED(rv)) {
1787 return rv;
1790 // Now, layer ourselves on top of the SSL socket...
1791 PRFileDesc* layer =
1792 PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
1793 &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
1794 if (!layer) {
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
1803 // will also leak.
1804 layer->secret = (PRFilePrivate*)do_AddRef(infoObject).take();
1806 if (PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer) !=
1807 PR_SUCCESS) {
1808 layer->dtor(layer);
1809 return NS_ERROR_FAILURE;
1811 auto layerCleanup = MakeScopeExit([&fd] {
1812 PRFileDesc* layer =
1813 PR_PopIOLayer(fd, nsSSLIOLayerHelpers::nsSSLIOLayerIdentity);
1814 if (layer) {
1815 layer->dtor(layer);
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)) {
1826 return 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();
1839 return NS_OK;
1842 extern "C" {
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();
1854 if (!socketChild) {
1855 return;
1858 RefPtr<IPCClientCertsChild> ipcClientCertsActor(
1859 socketChild->GetIPCClientCertsActor());
1860 if (!ipcClientCertsActor) {
1861 return;
1863 nsTArray<IPCClientCertObject> objects;
1864 if (!ipcClientCertsActor->SendFindObjects(&objects)) {
1865 return;
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(),
1874 ctx);
1875 break;
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);
1883 break;
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);
1889 break;
1890 default:
1891 MOZ_ASSERT_UNREACHABLE("unhandled IPCClientCertObject type");
1892 break;
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();
1905 if (!socketChild) {
1906 return;
1909 RefPtr<IPCClientCertsChild> ipcClientCertsActor(
1910 socketChild->GetIPCClientCertsActor());
1911 if (!ipcClientCertsActor) {
1912 return;
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,
1919 &signature)) {
1920 return;
1922 cb(signature.data().Length(), signature.data().Elements(), ctx);
1924 } // extern "C"