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:
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",
],