commit a0fa4a8739b375abe44a5e0a2b3eca4ea6539c01
parent 7df21e38f01c5af446d8ac1de12a567ff3dcdfa4
Author: Sandra Qu <squiles@mozilla.com>
Date: Thu, 11 Dec 2025 16:38:13 +0000
Bug 1992375 - Visuals not matching Figma design for SEC_ERROR_UNTRUSTED_ISSUER r=niklas,fluent-reviewers,flod
Differential Revision: https://phabricator.services.mozilla.com/D270404
Diffstat:
4 files changed, 127 insertions(+), 0 deletions(-)
diff --git a/browser/base/content/test/about/browser.toml b/browser/base/content/test/about/browser.toml
@@ -42,6 +42,8 @@ support-files = [
["browser_aboutCertError_telemetry.js"]
+["browser_aboutCertError_untrustedIssuer.js"]
+
["browser_aboutDialog_distribution.js"]
skip-if = [
"os == 'win' && os_version == '11.26100' && arch == 'x86_64' && msix && verify-standalone",
diff --git a/browser/base/content/test/about/browser_aboutCertError_untrustedIssuer.js b/browser/base/content/test/about/browser_aboutCertError_untrustedIssuer.js
@@ -0,0 +1,101 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const BAD_CERT_PAGE = "https://expired.example.com/";
+const BAD_CERT_PATH =
+ "../../../../../security/manager/ssl/tests/mochitest/browser/revoked.pem";
+
+function pemToBase64(pem) {
+ return pem
+ .replace(/-----BEGIN CERTIFICATE-----/, "")
+ .replace(/-----END CERTIFICATE-----/, "")
+ .replace(/\s+/g, "");
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["test.wait300msAfterTabSwitch", true],
+ ["security.certerrors.felt-privacy-v1", true],
+ ],
+ });
+});
+
+add_task(async function checkUntrustedCertIssuerCopy() {
+ const pem = await IOUtils.readUTF8(getTestFilePath(BAD_CERT_PATH));
+ const certBase64 = pemToBase64(pem);
+ const tab = await openErrorPage(BAD_CERT_PAGE);
+ const browser = tab.linkedBrowser;
+
+ await SpecialPowers.spawn(browser, [certBase64], async cert => {
+ const mockErrorInfo = {
+ errorCodeString: "SEC_ERROR_UNTRUSTED_ISSUER",
+ errorIsOverridable: false,
+ channelStatus: 0,
+ overridableErrorCategory: "trust-error",
+ validNotBefore: Date.now() - 1000 * 1000,
+ validNotAfter: Date.now() + 1000 * 1000,
+ certValidityRangeNotBefore: Date.now() - 1000 * 1000,
+ certValidityRangeNotAfter: Date.now() + 1000 * 2000,
+ issuerCommonName: "Untrusted CA",
+ errorMessage: "Peer’s Certificate issuer is not recognized.",
+ hasHSTS: false,
+ hasHPKP: false,
+ certChainStrings: [cert],
+ };
+ content.document.getFailedCertSecurityInfo = () => mockErrorInfo;
+
+ const netErrorCard =
+ content.document.querySelector("net-error-card").wrappedJSObject;
+ const info = Cu.cloneInto(mockErrorInfo, netErrorCard);
+ netErrorCard.errorInfo = info;
+ netErrorCard.hideExceptionButton = netErrorCard.shouldHideExceptionButton();
+ await netErrorCard.getUpdateComplete();
+
+ netErrorCard.advancedButton.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(
+ netErrorCard.advancedButton,
+ {},
+ content
+ );
+
+ await ContentTaskUtils.waitForCondition(
+ () => ContentTaskUtils.isVisible(netErrorCard.advancedContainer),
+ "Advanced container is visible"
+ );
+
+ Assert.ok(
+ netErrorCard.advancedShowing,
+ "Advanced details are shown for certificates from untrusted issuers."
+ );
+
+ Assert.ok(
+ !netErrorCard.exceptionButton,
+ "Proceed button should be shown for certificates from untrusted issuers."
+ );
+ Assert.equal(
+ netErrorCard.certErrorIntro.dataset.l10nId,
+ "fp-certerror-intro",
+ "Using the 'certificate error' intro."
+ );
+ Assert.equal(
+ netErrorCard.whyDangerous.dataset.l10nId,
+ "fp-certerror-untrusted-issuer-why-dangerous-body",
+ "Using the 'untrusted issuer' variant of the 'Why Dangerous' copy."
+ );
+ Assert.equal(
+ netErrorCard.whatCanYouDo.dataset.l10nId,
+ "fp-certerror-untrusted-issuer-what-can-you-do-body",
+ "Using the 'untrusted issuer' variant of the 'What can you do' copy."
+ );
+ Assert.equal(
+ netErrorCard.learnMoreLink.getAttribute("support-page"),
+ "connection-not-secure",
+ "'Learn more' link points to the insecure connection errors support page."
+ );
+ });
+
+ await BrowserTestUtils.removeTab(tab);
+});
diff --git a/toolkit/content/net-error-card.mjs b/toolkit/content/net-error-card.mjs
@@ -61,6 +61,7 @@ export class NetErrorCard extends MozLitElement {
};
static ERROR_CODES = new Set([
+ "SEC_ERROR_UNTRUSTED_ISSUER",
"SEC_ERROR_REVOKED_CERTIFICATE",
"SEC_ERROR_UNKNOWN_ISSUER",
"SSL_ERROR_BAD_CERT_DOMAIN",
@@ -220,6 +221,7 @@ export class NetErrorCard extends MozLitElement {
introContentTemplate() {
switch (this.errorInfo.errorCodeString) {
+ case "SEC_ERROR_UNTRUSTED_ISSUER":
case "SEC_ERROR_REVOKED_CERTIFICATE":
case "SEC_ERROR_UNKNOWN_ISSUER":
case "SSL_ERROR_BAD_CERT_DOMAIN":
@@ -267,6 +269,21 @@ export class NetErrorCard extends MozLitElement {
let content;
switch (this.errorInfo.errorCodeString) {
+ case "SEC_ERROR_UNTRUSTED_ISSUER": {
+ content = this.advancedSectionTemplate({
+ whyDangerousL10nId:
+ "fp-certerror-untrusted-issuer-why-dangerous-body",
+ whyDangerousL10nArgs: {
+ hostname: this.hostname,
+ },
+ whatCanYouDoL10nId:
+ "fp-certerror-untrusted-issuer-what-can-you-do-body",
+ learnMoreL10nId: "fp-learn-more-about-cert-issues",
+ learnMoreSupportPage: "connection-not-secure",
+ viewCert: true,
+ });
+ break;
+ }
case "SEC_ERROR_REVOKED_CERTIFICATE": {
content = this.advancedSectionTemplate({
whyDangerousL10nId: "fp-certerror-revoked-why-dangerous-body",
diff --git a/toolkit/locales/en-US/toolkit/neterror/certError.ftl b/toolkit/locales/en-US/toolkit/neterror/certError.ftl
@@ -196,6 +196,13 @@ fp-certerror-bad-domain-why-dangerous-body = The site is set up to allow only se
fp-certerror-bad-domain-what-can-you-do-body = Probably nothing, since it’s likely there’s a problem with the site itself. Sites use certificates issued by a certificate authority to prove they’re really who they say they are. But if you’re on a corporate network, your support team may have more info. If you’re using antivirus software, try searching for potential conflicts or known issues.
# This string appears after the following string: "What makes the site look dangerous?" (fp-certerror-why-site-dangerous)
+# Variables:
+# $hostname (String) - Hostname of the website to which the user was trying to connect.
+fp-certerror-untrusted-issuer-why-dangerous-body = { -brand-short-name } is warning you about this site because the certificate provided for { $hostname } was issued by a certificate authority that isn’t trusted anymore.
+# This string appears after the following string: "What can you do about it?" (fp-certerror-what-can-you-do)
+fp-certerror-untrusted-issuer-what-can-you-do-body = Probably nothing, since it’s likely there’s a problem with the site itself. You can check with the website owner to see if they are working on the problem.
+
+# This string appears after the following string: "What makes the site look dangerous?" (fp-certerror-why-site-dangerous)
fp-certerror-unknown-issuer-why-dangerous-body = There’s an issue with the site’s certificate. It’s possible that a bad actor is trying to impersonate the site. Sites use certificates issued by a certificate authority to prove they’re really who they say they are. { -brand-short-name } doesn’t trust this site because we can’t tell who issued the certificate, it’s self-signed, or the site isn’t sending intermediate certificates we trust.
# This string appears after the following string: "What can you do about it?" (fp-certerror-what-can-you-do)
fp-certerror-unknown-issuer-what-can-you-do-body = Probably nothing, since it’s likely there’s a problem with the site itself. But if you’re on a corporate network, your support team may have more info. If you’re using antivirus software, it may need to be configured to work with { -brand-short-name }.