tor-browser

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

commit 976e9d6b7765a48f0a75513f45c5e73c4d99fc49
parent b7e1499bbcf76678201f41b969d5cc081201141d
Author: Maile Lucks <maile.lucks@gmail.com>
Date:   Thu, 30 Oct 2025 19:38:11 +0000

Bug 1991887 - Add MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY to net-error-card component - r=jaws,fluent-reviewers,bolsson

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

Diffstat:
Mbrowser/base/content/test/about/browser_aboutCertError.js | 96++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtoolkit/content/net-error-card.mjs | 22++++++++++++++++++++++
Mtoolkit/locales/en-US/toolkit/neterror/certError.ftl | 9+++++++++
3 files changed, 126 insertions(+), 1 deletion(-)

diff --git a/browser/base/content/test/about/browser_aboutCertError.js b/browser/base/content/test/about/browser_aboutCertError.js @@ -107,7 +107,7 @@ add_task(async function checkReturnToAboutHome() { BrowserTestUtils.removeTab(gBrowser.selectedTab); } - SpecialPowers.popPrefEnv(); + await SpecialPowers.popPrefEnv(); } }); @@ -699,6 +699,100 @@ add_task(async function testCertificateTransparency() { // debug builds. }).skip(!AppConstants.DEBUG); +add_task(async function testCertificateTransparency_feltPrivacyTrue() { + info( + "Test that when certificate transparency is enforced, the right error page is shown." + ); + // Enforce certificate transparency for certificates issued by our test root. + // This is only possible in debug builds, hence skipping this test in + // non-debug builds (see below). + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.pki.certificate_transparency.mode", 2], + [ + "security.test.built_in_root_hash", + "8D:9D:57:09:E5:7D:D5:C6:4B:BE:24:70:E9:E5:BF:FF:16:F6:F2:C2:49:4E:0F:B9:37:1C:DD:3A:0E:10:45:F4", + ], + ["security.certerrors.felt-privacy-v1", true], + ], + }); + + for (let useFrame of [false, true]) { + const tab = await openErrorPage(GOOD_PAGE, useFrame); + const browser = tab.linkedBrowser; + + let bc = browser.browsingContext; + if (useFrame) { + bc = bc.children[0]; + } + + const message = await SpecialPowers.spawn(bc, [], async function () { + const doc = content.document; + + const netErrorCard = doc.querySelector("net-error-card").wrappedJSObject; + await netErrorCard.getUpdateComplete(); + + netErrorCard.advancedButton.scrollIntoView(); + EventUtils.synthesizeMouseAtCenter( + netErrorCard.advancedButton, + {}, + content + ); + + await ContentTaskUtils.waitForCondition(() => { + return ( + netErrorCard.whyDangerous && + netErrorCard.whyDangerous.textContent != "" + ); + }, "Waiting for why dangerous text"); + const args = JSON.parse(netErrorCard.whyDangerous.dataset.l10nArgs); + Assert.strictEqual( + args.hostname, + "example.com", + "Should list hostname in error message." + ); + + // Wait until fluent sets the errorCode inner text. + await ContentTaskUtils.waitForCondition(() => { + return ( + netErrorCard.errorCode && netErrorCard.errorCode.textContent != "" + ); + }, "error code has been set inside the advanced button panel"); + + netErrorCard.errorCode.scrollIntoView(); + EventUtils.synthesizeMouseAtCenter(netErrorCard.errorCode, {}, content); + await ContentTaskUtils.waitForCondition(() => { + return ( + netErrorCard.certErrorText && + netErrorCard.certErrorText.textContent != "" + ); + }, "Certificate Error is showing"); + + return { + certText: netErrorCard.certErrorText.textContent, + errorCode: netErrorCard.errorCode.textContent, + tagName: netErrorCard.errorCode.tagName.toLowerCase(), + }; + }); + + Assert.ok( + message.errorCode.includes( + "MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY" + ), + "Correct error message found" + ); + Assert.strictEqual(message.tagName, "a", "Error message is a link"); + Assert.ok(message.certText.includes(GOOD_PAGE), "Correct URL found"); + + BrowserTestUtils.removeTab(gBrowser.selectedTab); + } + + await SpecialPowers.popPrefEnv(); + + // Certificate transparency can only be enforced for our test certificates in + // debug builds. +}).skip(!AppConstants.DEBUG); + /** * A reusable helper that runs assertions on a network error page. * It encapsulates the SpecialPowers.spawn call to be CSP-compliant. diff --git a/toolkit/content/net-error-card.mjs b/toolkit/content/net-error-card.mjs @@ -44,6 +44,7 @@ export class NetErrorCard extends MozLitElement { returnButton: "#returnButton", learnMoreLink: "#learnMoreLink", whatCanYouDo: "#whatCanYouDo", + whyDangerous: "#fp-why-site-dangerous", }; static ERROR_CODES = new Set([ @@ -53,6 +54,7 @@ export class NetErrorCard extends MozLitElement { "SEC_ERROR_EXPIRED_CERTIFICATE", "SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE", "SSL_ERROR_NO_CYPHER_OVERLAP", + "MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY", ]); constructor() { @@ -154,6 +156,11 @@ export class NetErrorCard extends MozLitElement { data-l10n-id="fp-neterror-connection-intro" data-l10n-args='{"hostname": "${this.hostname}"}' ></p>`; + case "MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY": + return html`<p + data-l10n-id="fp-certerror-transparency-intro" + data-l10n-args='{"hostname": "${this.hostname}"}' + ></p>`; } return null; @@ -282,6 +289,20 @@ export class NetErrorCard extends MozLitElement { }); break; } + case "MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY": { + content = this.advancedSectionTemplate({ + whyDangerousL10nId: "fp-certerror-transparency-why-dangerous-body", + whyDangerousL10nArgs: { + hostname: this.hostname, + }, + whatCanYouDoL10nId: "fp-certerror-transparency-what-can-you-do-body", + learnMoreL10nId: "fp-learn-more-about-secure-connection-failures", + learnMoreSupportPage: "connection-not-secure", + viewCert: true, + proceedButton: true, + }); + break; + } } return html`<div class="advanced-container"> @@ -310,6 +331,7 @@ export class NetErrorCard extends MozLitElement { data-l10n-id="fp-certerror-why-site-dangerous" ></strong> <span + id="fp-why-site-dangerous" data-l10n-id=${whyDangerousL10nId} data-l10n-args=${JSON.stringify(whyDangerousL10nArgs)} ></span>` diff --git a/toolkit/locales/en-US/toolkit/neterror/certError.ftl b/toolkit/locales/en-US/toolkit/neterror/certError.ftl @@ -173,6 +173,7 @@ fp-certerror-hide-advanced-button = Hide advanced fp-certerror-override-exception-button = Proceed to { $hostname } (Risky) fp-certerror-intro = { -brand-short-name } spotted a potentially serious security issue with <strong>{ $hostname }</strong>. Someone pretending to be the site could try to steal things like credit card info, passwords, or emails. fp-certerror-expired-into = { -brand-short-name } spotted a security issue with <strong>{ $hostname }</strong>. Either the site isn’t set up right or your device’s clock is set to the wrong date/time. +fp-certerror-transparency-intro = Someone pretending to be <strong>{ $hostname }</strong> could try to steal things like credit card info, passwords, or emails. ## @@ -221,6 +222,14 @@ fp-cert-error-code = Error Code: { $error } # $datetime (Date) - Current datetime. fp-datetime = { DATETIME($datetime, month: "short", year: "numeric", day: "numeric") } { DATETIME($datetime, timeStyle: "long") } +# 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-transparency-why-dangerous-body = { -brand-short-name } doesn’t trust { $hostname } because it couldn’t prove it meets public certificate transparency requirements. +# This string appears after the following string: "What can you do about it?" (fp-certerror-what-can-you-do) +fp-certerror-transparency-what-can-you-do-body = Probably nothing, since it’s likely there’s a problem with the site itself. + + fp-learn-more-about-secure-connection-failures = Learn more about secure connection failures fp-learn-more-about-cert-issues = Learn more about these kinds of certificate issues fp-learn-more-about-time-related-errors = Learn more about troubleshooting time-related errors