tor-browser

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

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:
Mbrowser/base/content/test/about/browser.toml | 2++
Abrowser/base/content/test/about/browser_aboutCertError_untrustedIssuer.js | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/content/net-error-card.mjs | 17+++++++++++++++++
Mtoolkit/locales/en-US/toolkit/neterror/certError.ftl | 7+++++++
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 }.