tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 8cba26db617e077a84a1165208354b0f1c4715f3
parent 840cb3f998f2bccf2640714e1e7eab03edee26ad
Author: Jack Brown <jbrown@mozilla.com>
Date:   Thu,  8 Jan 2026 17:50:23 +0000

Bug 2006790 - Enable SSL_ERROR_NO_CYPHER_OVERLAP for Felt Privacy - r=niklas

Differential Revision: https://phabricator.services.mozilla.com/D277514

Diffstat:
Mbrowser/base/content/test/about/browser_aboutNetError.js | 29+++++++++++++++++++++++++++++
Mtoolkit/content/aboutNetError.mjs | 34++++++----------------------------
Mtoolkit/content/aboutNetErrorHelpers.mjs | 30++++++++++++++++++++++++++++++
Mtoolkit/content/net-error-card.mjs | 57++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mtoolkit/modules/RemotePageAccessManager.sys.mjs | 3+++
5 files changed, 120 insertions(+), 33 deletions(-)

diff --git a/browser/base/content/test/about/browser_aboutNetError.js b/browser/base/content/test/about/browser_aboutNetError.js @@ -299,6 +299,35 @@ add_task(async function onlyAllow3DESWithDeprecatedTLS() { async browser => { BrowserTestUtils.startLoadingURIString(browser, TRIPLEDES_PAGE); await BrowserTestUtils.waitForErrorPage(browser); + await SpecialPowers.spawn(browser, [], async function () { + const doc = content.document; + const netErrorCard = + doc.querySelector("net-error-card")?.wrappedJSObject; + Assert.ok(netErrorCard, "netErrorCard is rendered."); + + netErrorCard.advancedButton.scrollIntoView(); + EventUtils.synthesizeMouseAtCenter( + netErrorCard.advancedButton, + {}, + content + ); + await ContentTaskUtils.waitForCondition( + () => ContentTaskUtils.isVisible(netErrorCard.advancedContainer), + "Advanced container is visible" + ); + + const prefResetButton = netErrorCard.prefResetButton; + Assert.ok(prefResetButton, "prefResetButton exists in the DOM."); + netErrorCard.prefResetButton.scrollIntoView(); + await ContentTaskUtils.waitForCondition( + () => ContentTaskUtils.isVisible(netErrorCard.prefResetButton), + "Pref reset button is visible" + ); + ok( + ContentTaskUtils.isVisible(prefResetButton), + "prefResetButton is visible" + ); + }); } ); diff --git a/toolkit/content/aboutNetError.mjs b/toolkit/content/aboutNetError.mjs @@ -18,6 +18,7 @@ import { getCSSClass, gNoConnectivity, retryThis, + handleNSSFailure, errorHasNoUserFix, COOP_MDN_DOCS, COEP_MDN_DOCS, @@ -373,35 +374,12 @@ function initTitleAndBodyIds(baseURL, isTRROnlyFailure) { // failures) are of type nssFailure2. case "nssFailure2": { learnMore.hidden = false; - - const netErrorInfo = document.getNetErrorInfo(); - void recordSecurityUITelemetry( - "securityUiTlserror", - "loadAbouttlserror", - netErrorInfo - ); - const errorCode = netErrorInfo.errorCodeString; - switch (errorCode) { - case "SSL_ERROR_UNSUPPORTED_VERSION": - case "SSL_ERROR_PROTOCOL_VERSION_ALERT": { - const tlsNotice = document.getElementById("tlsVersionNotice"); - tlsNotice.hidden = false; - document.l10n.setAttributes(tlsNotice, "cert-error-old-tls-version"); - } - // fallthrough - - case "SSL_ERROR_NO_CIPHERS_SUPPORTED": - case "SSL_ERROR_NO_CYPHER_OVERLAP": - case "SSL_ERROR_SSL_DISABLED": - RPMAddMessageListener("HasChangedCertPrefs", msg => { - if (msg.data.hasChangedCertPrefs) { - // Configuration overrides might have caused this; offer to reset. - showPrefChangeContainer(); - } - }); - RPMSendAsyncMessage("GetChangedCertPrefs"); + const result = handleNSSFailure(showPrefChangeContainer); + if (result.versionError) { + const tlsNotice = document.getElementById("tlsVersionNotice"); + tlsNotice.hidden = false; + document.l10n.setAttributes(tlsNotice, "cert-error-old-tls-version"); } - break; } diff --git a/toolkit/content/aboutNetErrorHelpers.mjs b/toolkit/content/aboutNetErrorHelpers.mjs @@ -194,3 +194,33 @@ export function errorHasNoUserFix(errorCodeString) { return false; } } + +export function handleNSSFailure(callback) { + const netErrorInfo = document.getNetErrorInfo(); + void recordSecurityUITelemetry( + "securityUiTlserror", + "loadAbouttlserror", + netErrorInfo + ); + const errorCode = netErrorInfo.errorCodeString; + const result = {}; + switch (errorCode) { + case "SSL_ERROR_UNSUPPORTED_VERSION": + case "SSL_ERROR_PROTOCOL_VERSION_ALERT": { + result.versionError = true; + } + // fallthrough + + case "SSL_ERROR_NO_CIPHERS_SUPPORTED": + case "SSL_ERROR_NO_CYPHER_OVERLAP": + case "SSL_ERROR_SSL_DISABLED": + RPMAddMessageListener("HasChangedCertPrefs", msg => { + if (msg.data.hasChangedCertPrefs) { + // Configuration overrides might have caused this; offer to reset. + callback?.(); + } + }); + RPMSendAsyncMessage("GetChangedCertPrefs"); + } + return result; +} diff --git a/toolkit/content/net-error-card.mjs b/toolkit/content/net-error-card.mjs @@ -13,6 +13,7 @@ import { getHostName, getSubjectAltNames, getFailedCertificatesAsPEMString, + handleNSSFailure, recordSecurityUITelemetry, gOffline, retryThis, @@ -40,6 +41,7 @@ export class NetErrorCard extends MozLitElement { advancedShowing: { type: Boolean, reflect: true }, certErrorDebugInfoShowing: { type: Boolean, reflect: true }, certificateErrorText: { type: String }, + showPrefReset: { type: Boolean }, }; static queries = { @@ -63,6 +65,7 @@ export class NetErrorCard extends MozLitElement { netErrorLearnMoreLink: "#neterror-learn-more-link", httpAuthIntroText: "#fp-http-auth-disabled-intro-text", tryAgainButton: "#tryAgainButton", + prefResetButton: "#prefResetButton", }; static NSS_ERRORS = [ @@ -93,7 +96,7 @@ export class NetErrorCard extends MozLitElement { "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT", "SEC_ERROR_EXPIRED_CERTIFICATE", "SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE", - // Bug #2006790 - Temporarily disabling SSL_ERROR_NO_CYPHER_OVERLAP until we create a pref reset button. + "SSL_ERROR_NO_CYPHER_OVERLAP", "MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY", "NS_ERROR_OFFLINE", "NS_ERROR_DOM_COOP_FAILED", @@ -154,6 +157,7 @@ export class NetErrorCard extends MozLitElement { this.domainMismatchNamesPromise = null; this.certificateErrorTextPromise = null; this.showCustomNetErrorCard = false; + this.showPrefReset = false; } async getUpdateComplete() { @@ -258,6 +262,47 @@ export class NetErrorCard extends MozLitElement { } } + handlePrefChangeDetected() { + this.showPrefReset = true; + this.focusPrefResetButton(); + } + + async focusPrefResetButton() { + await this.getUpdateComplete(); + + if (window.top != window) { + return; + } + + if (!this.prefResetButton) { + return; + } + + requestAnimationFrame(() => { + this.prefResetButton.focus(); + }); + } + + handlePrefResetClick() { + RPMSendAsyncMessage("Browser:ResetSSLPreferences"); + } + + prefResetContainerTemplate() { + if (!this.showPrefReset) { + return null; + } + + return html`<div id="prefChangeContainer" class="button-container"> + <p data-l10n-id="neterror-pref-reset"></p> + <moz-button + id="prefResetButton" + type="primary" + data-l10n-id="neterror-pref-reset-button" + @click=${this.handlePrefResetClick} + ></moz-button> + </div>`; + } + getErrorInfo() { const errorInfo = gIsCertError ? document.getFailedCertSecurityInfo() @@ -267,6 +312,10 @@ export class NetErrorCard extends MozLitElement { this.showCustomNetErrorCard = true; errorInfo.errorCodeString = NetErrorCard.getCustomErrorCode(gErrorCode); } + + if (gErrorCode === "nssFailure2") { + handleNSSFailure(() => this.handlePrefChangeDetected()); + } return errorInfo; } @@ -482,10 +531,7 @@ export class NetErrorCard extends MozLitElement { content = this.advancedSectionTemplate({ whyDangerousL10nId: "fp-neterror-cypher-overlap-why-dangerous-body", whatCanYouDoL10nId: "fp-neterror-cypher-overlap-what-can-you-do-body", - learnMoreL10nId: "fp-cert-error-code", - learnMoreL10nArgs: { - error: this.errorInfo.errorCodeString, - }, + learnMoreL10nId: "fp-learn-more-about-secure-connection-failures", learnMoreSupportPage: "connection-not-secure", }); break; @@ -607,6 +653,7 @@ export class NetErrorCard extends MozLitElement { </div>` : null} ${importantNote ? html`<p data-l10n-id=${importantNote}></p>` : null} + ${this.prefResetContainerTemplate()} ${viewCert ? html`<p> <a diff --git a/toolkit/modules/RemotePageAccessManager.sys.mjs b/toolkit/modules/RemotePageAccessManager.sys.mjs @@ -108,6 +108,9 @@ export let RemotePageAccessManager = { "network.trr_ui.skip_reason_learn_more_url", ], RPMGetBoolPref: [ + "security.certerrors.mitm.priming.enabled", + "security.certerrors.permanentOverride", + "security.enterprise_roots.auto-enabled", "security.certerror.hideAddException", "security.certerrors.felt-privacy-v1", ],