commit 4e6368b8e07f48339d6730e36c2be297e3bf1d6c
parent 2c0e59dd8de119516c14f0aa224da19bbad8dc84
Author: Jack Brown <jbrown@mozilla.com>
Date: Wed, 10 Dec 2025 18:47:03 +0000
Bug 1992384 - Add MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE support to net-error-card - r=niklas,fluent-reviewers,bolsson
Differential Revision: https://phabricator.services.mozilla.com/D274174
Diffstat:
4 files changed, 133 insertions(+), 0 deletions(-)
diff --git a/browser/base/content/test/about/browser.toml b/browser/base/content/test/about/browser.toml
@@ -32,6 +32,8 @@ support-files = [
["browser_aboutCertError_noSubjectAltName.js"]
+["browser_aboutCertError_notYetValid.js"]
+
["browser_aboutCertError_offlineSupport.js"]
["browser_aboutCertError_offlineSupport_feltPrivacyV1.js"]
diff --git a/browser/base/content/test/about/browser_aboutCertError_notYetValid.js b/browser/base/content/test/about/browser_aboutCertError_notYetValid.js
@@ -0,0 +1,100 @@
+/* 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 NOT_YET_VALID_CERT_PATH =
+ "../../../../../security/manager/ssl/tests/mochitest/browser/ca.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 testNotYetValidCert() {
+ const pem = await IOUtils.readUTF8(getTestFilePath(NOT_YET_VALID_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: "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE",
+ errorIsOverridable: false,
+ channelStatus: 0,
+ overridableErrorCategory: "expired-or-not-yet-valid",
+ validNotBefore: Date.now() + 1000 * 1000,
+ validNotAfter: Date.now() + 1000 * 2000,
+ certValidityRangeNotBefore: Date.now() + 1000 * 1000,
+ certValidityRangeNotAfter: Date.now() + 1000 * 2000,
+ issuerCommonName: "Test CA",
+ errorMessage: "The server presented a certificate that is not yet valid.",
+ 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;
+ 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 not-yet-valid certificates."
+ );
+ Assert.ok(
+ netErrorCard.exceptionButton,
+ "Proceed button should be shown for not-yet-valid certificates."
+ );
+ Assert.equal(
+ netErrorCard.certErrorIntro.dataset.l10nId,
+ "fp-certerror-intro",
+ "Using the 'certificate error' intro."
+ );
+ Assert.equal(
+ netErrorCard.whyDangerous.dataset.l10nId,
+ "fp-certerror-pkix-not-yet-valid-why-dangerous-body",
+ "Using the 'not yet valid' variant of the 'Why Dangerous' copy."
+ );
+ Assert.equal(
+ netErrorCard.whatCanYouDo.dataset.l10nId,
+ "fp-certerror-pkix-not-yet-valid-what-can-you-do-body",
+ "Using the 'not yet valid' variant of the 'What can you do' copy."
+ );
+ Assert.equal(
+ netErrorCard.learnMoreLink.getAttribute("support-page"),
+ "time-errors",
+ "'Learn more' link points to the time-related errors support page."
+ );
+ });
+
+ await BrowserTestUtils.removeTab(tab);
+});
diff --git a/toolkit/content/net-error-card.mjs b/toolkit/content/net-error-card.mjs
@@ -72,6 +72,7 @@ export class NetErrorCard extends MozLitElement {
"NS_ERROR_OFFLINE",
"NS_ERROR_DOM_COOP_FAILED",
"NS_ERROR_DOM_COEP_FAILED",
+ "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE",
]);
static isSupported() {
@@ -224,6 +225,7 @@ export class NetErrorCard extends MozLitElement {
case "SSL_ERROR_BAD_CERT_DOMAIN":
case "SEC_ERROR_EXPIRED_CERTIFICATE":
case "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT":
+ case "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE":
return html`<p
id="certErrorIntro"
data-l10n-id="fp-certerror-intro"
@@ -399,6 +401,25 @@ export class NetErrorCard extends MozLitElement {
});
break;
}
+ case "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE": {
+ const notBefore = this.errorInfo.validNotBefore;
+ content = this.advancedSectionTemplate({
+ whyDangerousL10nId:
+ "fp-certerror-pkix-not-yet-valid-why-dangerous-body",
+ whyDangerousL10nArgs: {
+ date: notBefore,
+ },
+ whatCanYouDoL10nId:
+ "fp-certerror-pkix-not-yet-valid-what-can-you-do-body",
+ whatCanYouDoL10nArgs: {
+ date: Date.now(),
+ },
+ learnMoreL10nId: "fp-learn-more-about-time-related-errors",
+ learnMoreSupportPage: "time-errors",
+ viewCert: true,
+ });
+ break;
+ }
}
return html`<div class="advanced-container">
diff --git a/toolkit/locales/en-US/toolkit/neterror/certError.ftl b/toolkit/locales/en-US/toolkit/neterror/certError.ftl
@@ -240,3 +240,13 @@ fp-certerror-transparency-what-can-you-do-body = Probably nothing, since it’s
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
+
+# This string appears after the following string: "What makes the site look dangerous?" (fp-certerror-why-site-dangerous)
+# Variables:
+# $datetime (Date) - Date the cert becomes valid.
+fp-certerror-pkix-not-yet-valid-why-dangerous-body = { -brand-short-name } doesn’t trust this site because it looks like the certificate provided isn’t valid until { DATETIME($date, timeStyle: "short") } on { DATETIME($date, month: "numeric", day: "numeric", year: "numeric") }.
+
+# This string appears after the following string: "What can you do about it?" (fp-certerror-what-can-you-do)
+# Variables:
+# $date (Date) - Device's clock date.
+fp-certerror-pkix-not-yet-valid-what-can-you-do-body = Your device’s clock is set to { DATETIME($date, timeStyle: "short") } { DATETIME($date, month: "numeric", day: "numeric", year: "numeric") }. If this is correct, the security issue is probably with the site itself. If it’s wrong, you can change it in your device’s system settings.