Bug 1552333 - Move onCertErrorDetails from NetErrorChild.jsm to aboutNetError.js. r=johannh,flod,fluent-reviewers

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
prathiksha 2019-06-18 03:54:21 +00:00
Родитель beb8201a97
Коммит b901cf9927
12 изменённых файлов: 394 добавлений и 407 удалений

Просмотреть файл

@ -17,44 +17,19 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
return Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
});
XPCOMUtils.defineLazyPreferenceGetter(this, "mitmErrorPageEnabled",
"browser.security.newcerterrorpage.mitm.enabled");
XPCOMUtils.defineLazyPreferenceGetter(this, "mitmPrimingEnabled",
"security.certerrors.mitm.priming.enabled");
XPCOMUtils.defineLazyGetter(this, "gNSSErrorsBundle", function() {
return Services.strings.createBundle("chrome://pipnss/locale/nsserrors.properties");
});
const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.MOZILLA_PKIX_ERROR_BASE;
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = SEC_ERROR_BASE + 30;
const SEC_ERROR_REUSED_ISSUER_AND_SERIAL = SEC_ERROR_BASE + 138;
const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144;
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 5;
const MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = MOZILLA_PKIX_ERROR_BASE + 6;
const MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED = MOZILLA_PKIX_ERROR_BASE + 13;
const MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT = MOZILLA_PKIX_ERROR_BASE + 14;
const MOZILLA_PKIX_ERROR_MITM_DETECTED = MOZILLA_PKIX_ERROR_BASE + 15;
const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12;
const SSL_ERROR_SSL_DISABLED = SSL_ERROR_BASE + 20;
const SSL_ERROR_SSL2_DISABLED = SSL_ERROR_BASE + 14;
const PREF_SERVICES_SETTINGS_CLOCK_SKEW_SECONDS = "services.settings.clock_skew_seconds";
const PREF_SERVICES_SETTINGS_LAST_FETCHED = "services.settings.last_update_seconds";
const PREF_SSL_IMPACT_ROOTS = ["security.tls.version.", "security.ssl3."];
let formatter = new Services.intl.DateTimeFormat(undefined, {
dateStyle: "long",
});
function getSerializedSecurityInfo(docShell) {
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
@ -86,287 +61,6 @@ class NetErrorChild extends ActorChild {
};
}
_getCertValidityRange(docShell) {
let {securityInfo} = docShell.failedChannel;
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
let notBefore = 0;
let notAfter = Number.MAX_SAFE_INTEGER;
for (let cert of securityInfo.failedCertChain.getEnumerator()) {
notBefore = Math.max(notBefore, cert.validity.notBefore);
notAfter = Math.min(notAfter, cert.validity.notAfter);
}
// nsIX509Cert reports in PR_Date terms, which uses microseconds. Convert:
notBefore /= 1000;
notAfter /= 1000;
return {notBefore, notAfter};
}
// eslint-disable-next-line complexity
onCertErrorDetails(msg, docShell) {
let doc = docShell.document;
// This function centers the error container after its content updates.
// It is currently duplicated in aboutNetError.js to avoid having to do
// async communication to the page that would result in flicker.
// TODO(johannh): Get rid of this duplication.
function updateContainerPosition() {
let textContainer = doc.getElementById("text-container");
// Using the vh CSS property our margin adapts nicely to window size changes.
// Unfortunately, this doesn't work correctly in iframes, which is why we need
// to manually compute the height there.
if (doc.ownerGlobal.parent == doc.ownerGlobal) {
textContainer.style.marginTop = `calc(50vh - ${textContainer.clientHeight / 2}px)`;
} else {
let offset = (doc.documentElement.clientHeight / 2) - (textContainer.clientHeight / 2);
if (offset > 0) {
textContainer.style.marginTop = `${offset}px`;
}
}
}
// Check if the connection is being man-in-the-middled. When the parent
// detects an intercepted connection, the page may be reloaded with a new
// error code (MOZILLA_PKIX_ERROR_MITM_DETECTED).
if (mitmPrimingEnabled && msg.data.code == SEC_ERROR_UNKNOWN_ISSUER &&
// Only do this check for top-level failures.
doc.ownerGlobal.top === doc.ownerGlobal) {
this.mm.sendAsyncMessage("Browser:PrimeMitm");
}
let div = doc.getElementById("certificateErrorText");
div.textContent = msg.data.info;
let learnMoreLink = doc.getElementById("learnMoreLink");
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
learnMoreLink.setAttribute("href", baseURL + "connection-not-secure");
let errWhatToDo = doc.getElementById("es_nssBadCert_" + msg.data.codeString);
let es = doc.getElementById("errorWhatToDoText");
let errWhatToDoTitle = doc.getElementById("edd_nssBadCert");
let est = doc.getElementById("errorWhatToDoTitleText");
let searchParams = new URLSearchParams(doc.documentURI.split("?")[1]);
let error = searchParams.get("e");
if (error == "sslv3Used") {
learnMoreLink.setAttribute("href", baseURL + "sslv3-error-messages");
}
if (error == "nssFailure2") {
let shortDesc = doc.getElementById("errorShortDescText").textContent;
// nssFailure2 also gets us other non-overrideable errors. Choose
// a "learn more" link based on description:
if (shortDesc.includes("MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE")) {
learnMoreLink.setAttribute("href", baseURL + "certificate-pinning-reports");
}
}
// This is set to true later if the user's system clock is at fault for this error.
let clockSkew = false;
doc.body.setAttribute("code", msg.data.codeString);
// Need to do this here (which is not exactly at load but a few ticks later),
// because this is the first time we have access to the error code.
this.recordLoadEvent(doc);
switch (msg.data.code) {
case SSL_ERROR_BAD_CERT_DOMAIN:
case SEC_ERROR_OCSP_INVALID_SIGNING_CERT:
case SEC_ERROR_UNKNOWN_ISSUER:
if (es) {
// eslint-disable-next-line no-unsanitized/property
es.innerHTML = errWhatToDo.innerHTML;
}
if (est) {
// eslint-disable-next-line no-unsanitized/property
est.innerHTML = errWhatToDoTitle.innerHTML;
}
updateContainerPosition();
break;
// This error code currently only exists for the Symantec distrust
// in Firefox 63, so we add copy explaining that to the user.
// In case of future distrusts of that scale we might need to add
// additional parameters that allow us to identify the affected party
// without replicating the complex logic from certverifier code.
case MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED:
let description = gPipNSSBundle.formatStringFromName(
"certErrorSymantecDistrustDescription1", [doc.location.hostname]);
let descriptionContainer = doc.getElementById("errorShortDescText2");
descriptionContainer.textContent = description;
let adminDescription = doc.createElement("p");
adminDescription.textContent =
gPipNSSBundle.GetStringFromName("certErrorSymantecDistrustAdministrator");
descriptionContainer.append(adminDescription);
learnMoreLink.href = baseURL + "symantec-warning";
updateContainerPosition();
break;
case MOZILLA_PKIX_ERROR_MITM_DETECTED:
if (mitmErrorPageEnabled) {
let autoEnabledEnterpriseRoots =
Services.prefs.getBoolPref("security.enterprise_roots.auto-enabled", false);
if (mitmPrimingEnabled && autoEnabledEnterpriseRoots) {
// If we automatically tried to import enterprise root certs but it didn't
// fix the MITM, reset the pref.
this.mm.sendAsyncMessage("Browser:ResetEnterpriseRootsPref");
}
// We don't actually know what the MitM is called (since we don't
// maintain a list), so we'll try and display the common name of the
// root issuer to the user. In the worst case they are as clueless as
// before, in the best case this gives them an actionable hint.
// This may be revised in the future.
let {securityInfo} = docShell.failedChannel;
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
let mitmName = null;
for (let cert of securityInfo.failedCertChain.getEnumerator()) {
mitmName = cert.issuerCommonName;
}
for (let span of doc.querySelectorAll(".mitm-name")) {
span.textContent = mitmName;
}
learnMoreLink.href = baseURL + "security-error";
let title = doc.getElementById("et_mitm");
let desc = doc.getElementById("ed_mitm");
doc.querySelector(".title-text").textContent = title.textContent;
// eslint-disable-next-line no-unsanitized/property
doc.getElementById("errorShortDescText").innerHTML = desc.innerHTML;
// eslint-disable-next-line no-unsanitized/property
es.innerHTML = errWhatToDo.innerHTML;
// eslint-disable-next-line no-unsanitized/property
est.innerHTML = errWhatToDoTitle.innerHTML;
updateContainerPosition();
break;
}
// If the condition is false, fall through...
case MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT:
learnMoreLink.href = baseURL + "security-error";
break;
// In case the certificate expired we make sure the system clock
// matches the remote-settings service (blocklist via Kinto) ping time
// and is not before the build date.
case SEC_ERROR_EXPIRED_CERTIFICATE:
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
case MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
case MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
learnMoreLink.href = baseURL + "time-errors";
// We check against the remote-settings server time first if available, because that allows us
// to give the user an approximation of what the correct time is.
let difference = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_CLOCK_SKEW_SECONDS, 0);
let lastFetched = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_LAST_FETCHED, 0) * 1000;
let now = Date.now();
let certRange = this._getCertValidityRange(docShell);
let approximateDate = now - difference * 1000;
// If the difference is more than a day, we last fetched the date in the last 5 days,
// and adjusting the date per the interval would make the cert valid, warn the user:
if (Math.abs(difference) > 60 * 60 * 24 && (now - lastFetched) <= 60 * 60 * 24 * 5 &&
certRange.notBefore < approximateDate && certRange.notAfter > approximateDate) {
clockSkew = true;
// If there is no clock skew with Kinto servers, check against the build date.
// (The Kinto ping could have happened when the time was still right, or not at all)
} else {
let appBuildID = Services.appinfo.appBuildID;
let year = parseInt(appBuildID.substr(0, 4), 10);
let month = parseInt(appBuildID.substr(4, 2), 10) - 1;
let day = parseInt(appBuildID.substr(6, 2), 10);
let buildDate = new Date(year, month, day);
let systemDate = new Date();
// We don't check the notBefore of the cert with the build date,
// as it is of course almost certain that it is now later than the build date,
// so we shouldn't exclude the possibility that the cert has become valid
// since the build date.
if (buildDate > systemDate && new Date(certRange.notAfter) > buildDate) {
clockSkew = true;
}
}
let systemDate = formatter.format(new Date());
doc.getElementById("wrongSystemTime_systemDate1").textContent = systemDate;
if (clockSkew) {
doc.body.classList.add("illustrated", "clockSkewError");
let clockErrTitle = doc.getElementById("et_clockSkewError");
let clockErrDesc = doc.getElementById("ed_clockSkewError");
// eslint-disable-next-line no-unsanitized/property
doc.querySelector(".title-text").textContent = clockErrTitle.textContent;
let desc = doc.getElementById("errorShortDescText");
doc.getElementById("errorShortDesc").style.display = "block";
doc.getElementById("certificateErrorReporting").style.display = "none";
if (desc) {
// eslint-disable-next-line no-unsanitized/property
desc.innerHTML = clockErrDesc.innerHTML;
}
let errorPageContainer = doc.getElementById("errorPageContainer");
let textContainer = doc.getElementById("text-container");
errorPageContainer.style.backgroundPosition = `left top calc(50vh - ${textContainer.clientHeight / 2}px)`;
} else {
let targetElems = doc.querySelectorAll("#wrongSystemTime_systemDate2");
for (let elem of targetElems) {
elem.textContent = systemDate;
}
let errDesc = doc.getElementById("ed_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE");
let sd = doc.getElementById("errorShortDescText");
// eslint-disable-next-line no-unsanitized/property
sd.innerHTML = errDesc.innerHTML;
let span = sd.querySelector(".hostname");
span.textContent = doc.location.hostname;
// The secondary description mentions expired certificates explicitly
// and should only be shown if the certificate has actually expired
// instead of being not yet valid.
if (msg.data.code == SEC_ERROR_EXPIRED_CERTIFICATE) {
let {cssClass} = this.getParams(doc);
let stsSuffix = cssClass == "badStsCert" ? "_sts" : "";
let errDesc2 = doc.getElementById(
`ed2_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE${stsSuffix}`);
let sd2 = doc.getElementById("errorShortDescText2");
// eslint-disable-next-line no-unsanitized/property
sd2.innerHTML = errDesc2.innerHTML;
}
if (es) {
// eslint-disable-next-line no-unsanitized/property
es.innerHTML = errWhatToDo.innerHTML;
}
if (est) {
// eslint-disable-next-line no-unsanitized/property
est.textContent = errWhatToDoTitle.textContent;
est.style.fontWeight = "bold";
}
updateContainerPosition();
}
break;
}
// Add slightly more alarming UI unless there are indicators that
// show that the error is harmless or can not be skipped anyway.
let {cssClass} = this.getParams(doc);
// Don't alarm users when they can't continue to the website anyway...
if (cssClass != "badStsCert" &&
// Errors in iframes can't be skipped either...
doc.ownerGlobal.parent == doc.ownerGlobal &&
// Also don't bother if it's just the user's clock being off...
!clockSkew &&
// Symantec distrust is likely harmless as well.
msg.data.code != MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED) {
doc.body.classList.add("caution");
}
}
handleEvent(aEvent) {
// Documents have a null ownerDocument.
let doc = aEvent.originalTarget.ownerDocument || aEvent.originalTarget;
@ -405,7 +99,10 @@ class NetErrorChild extends ActorChild {
return;
}
this.onCertErrorDetails(msg, frameDocShell);
let data = msg.data;
let win = frameDocShell.document.ownerGlobal;
let event = Cu.cloneInto({ detail: data }, win);
win.dispatchEvent(new win.CustomEvent("ShowCertErrorDetails", event));
}
}
@ -547,16 +244,6 @@ class NetErrorChild extends ActorChild {
return searchParams.get("s");
}
recordLoadEvent(doc) {
let cssClass = this.getCSSClass(doc);
// Telemetry values for events are max. 80 bytes.
let errorCode = doc.body.getAttribute("code").substring(0, 40);
Services.telemetry.recordEvent("security.ui.certerror", "load", "aboutcerterror", errorCode, {
"has_sts": (cssClass == "badStsCert").toString(),
"is_frame": (doc.ownerGlobal.parent != doc.ownerGlobal).toString(),
});
}
recordClick(element) {
let telemetryId = element.dataset.telemetryId;
if (!telemetryId) {

Просмотреть файл

@ -1,5 +1,7 @@
/* eslint-env mozilla/frame-script */
const formatter = new Intl.DateTimeFormat("default");
// The following parameters are parsed from the error URL:
// e - the error code
// s - custom CSS class to allow alternate styling/favicons
@ -361,10 +363,248 @@ function initPageCertError() {
}
}, true, true);
let failedCertInfo = document.getFailedCertSecurityInfo();
RPMSendAsyncMessage("RecordCertErrorLoad", {
// Telemetry values for events are max. 80 bytes.
errorCode: failedCertInfo.errorCodeString.substring(0, 40),
has_sts: getCSSClass() == "badStsCert",
is_frame: window.parent != window,
});
window.addEventListener("ShowCertErrorDetails", setCertErrorDetails);
setTechnicalDetailsOnCertError();
let event = new CustomEvent("AboutNetErrorLoad", {bubbles: true});
document.getElementById("advancedButton").dispatchEvent(event);
}
setTechnicalDetailsOnCertError();
function setCertErrorDetails(event) {
// Check if the connection is being man-in-the-middled. When the parent
// detects an intercepted connection, the page may be reloaded with a new
// error code (MOZILLA_PKIX_ERROR_MITM_DETECTED).
let failedCertInfo = document.getFailedCertSecurityInfo();
let mitmPrimingEnabled = RPMGetBoolPref("security.certerrors.mitm.priming.enabled");
if (mitmPrimingEnabled &&
failedCertInfo.errorCodeString == "SEC_ERROR_UNKNOWN_ISSUER" &&
// Only do this check for top-level failures.
window.parent == window) {
RPMSendAsyncMessage("Browser:PrimeMitm");
}
let div = document.getElementById("certificateErrorText");
div.textContent = event.detail.info;
let learnMoreLink = document.getElementById("learnMoreLink");
let baseURL = RPMGetFormatURLPref("app.support.baseURL");
learnMoreLink.setAttribute("href", baseURL + "connection-not-secure");
let errWhatToDo = document.getElementById("es_nssBadCert_" + failedCertInfo.errorCodeString);
let es = document.getElementById("errorWhatToDoText");
let errWhatToDoTitle = document.getElementById("edd_nssBadCert");
let est = document.getElementById("errorWhatToDoTitleText");
let error = getErrorCode();
if (error == "sslv3Used") {
learnMoreLink.setAttribute("href", baseURL + "sslv3-error-messages");
}
if (error == "nssFailure2") {
let shortDesc = document.getElementById("errorShortDescText").textContent;
// nssFailure2 also gets us other non-overrideable errors. Choose
// a "learn more" link based on description:
if (shortDesc.includes("MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE")) {
learnMoreLink.setAttribute("href", baseURL + "certificate-pinning-reports");
}
}
// This is set to true later if the user's system clock is at fault for this error.
let clockSkew = false;
document.body.setAttribute("code", failedCertInfo.errorCodeString);
let desc;
switch (failedCertInfo.errorCodeString) {
case "SSL_ERROR_BAD_CERT_DOMAIN":
case "SEC_ERROR_OCSP_INVALID_SIGNING_CERT":
case "SEC_ERROR_UNKNOWN_ISSUER":
if (es) {
// eslint-disable-next-line no-unsanitized/property
es.innerHTML = errWhatToDo.innerHTML;
}
if (est) {
// eslint-disable-next-line no-unsanitized/property
est.innerHTML = errWhatToDoTitle.innerHTML;
}
updateContainerPosition();
break;
// This error code currently only exists for the Symantec distrust
// in Firefox 63, so we add copy explaining that to the user.
// In case of future distrusts of that scale we might need to add
// additional parameters that allow us to identify the affected party
// without replicating the complex logic from certverifier code.
case "MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED":
desc = document.getElementById("errorShortDescText2");
let hostname = document.location.hostname;
document.l10n.setAttributes(desc, "cert-error-symantec-distrust-description", {
hostname,
});
let adminDesc = document.createElement("p");
document.l10n.setAttributes(adminDesc, "cert-error-symantec-distrust-admin");
learnMoreLink.href = baseURL + "symantec-warning";
updateContainerPosition();
break;
case "MOZILLA_PKIX_ERROR_MITM_DETECTED":
let autoEnabledEnterpriseRoots = RPMGetBoolPref("security.enterprise_roots.auto-enabled");
if (mitmPrimingEnabled && autoEnabledEnterpriseRoots) {
RPMSendAsyncMessage("Browser:ResetEnterpriseRootsPref");
}
// We don't actually know what the MitM is called (since we don't
// maintain a list), so we'll try and display the common name of the
// root issuer to the user. In the worst case they are as clueless as
// before, in the best case this gives them an actionable hint.
// This may be revised in the future.
let names = document.querySelectorAll(".mitm-name");
for (let span of names) {
span.textContent = failedCertInfo.issuerCommonName;
}
learnMoreLink.href = baseURL + "security-error";
let title = document.getElementById("et_mitm");
desc = document.getElementById("ed_mitm");
document.querySelector(".title-text").textContent = title.textContent;
// eslint-disable-next-line no-unsanitized/property
document.getElementById("errorShortDescText").innerHTML = desc.innerHTML;
// eslint-disable-next-line no-unsanitized/property
es.innerHTML = errWhatToDo.innerHTML;
// eslint-disable-next-line no-unsanitized/property
est.innerHTML = errWhatToDoTitle.innerHTML;
updateContainerPosition();
break;
case "MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT":
learnMoreLink.href = baseURL + "security-error";
break;
// In case the certificate expired we make sure the system clock
// matches the remote-settings service (blocklist via Kinto) ping time
// and is not before the build date.
case "SEC_ERROR_EXPIRED_CERTIFICATE":
case "SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE":
case "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE":
case "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE":
learnMoreLink.href = baseURL + "time-errors";
// We check against the remote-settings server time first if available, because that allows us
// to give the user an approximation of what the correct time is.
let difference = event.detail.clockSkewDifference;
let lastFetched = event.detail.settingsLastFetched * 1000;
let now = Date.now();
let certRange = {
notBefore: failedCertInfo.certValidityRangeNotBefore,
notAfter: failedCertInfo.certValidityRangeNotAfter,
};
let approximateDate = now - difference * 1000;
// If the difference is more than a day, we last fetched the date in the last 5 days,
// and adjusting the date per the interval would make the cert valid, warn the user:
if (Math.abs(difference) > 60 * 60 * 24 && (now - lastFetched) <= 60 * 60 * 24 * 5 &&
certRange.notBefore < approximateDate && certRange.notAfter > approximateDate) {
clockSkew = true;
// If there is no clock skew with Kinto servers, check against the build date.
// (The Kinto ping could have happened when the time was still right, or not at all)
} else {
let appBuildID = event.detail.appBuildID;
let year = parseInt(appBuildID.substr(0, 4), 10);
let month = parseInt(appBuildID.substr(4, 2), 10) - 1;
let day = parseInt(appBuildID.substr(6, 2), 10);
let buildDate = new Date(year, month, day);
let systemDate = new Date();
// We don't check the notBefore of the cert with the build date,
// as it is of course almost certain that it is now later than the build date,
// so we shouldn't exclude the possibility that the cert has become valid
// since the build date.
if (buildDate > systemDate && new Date(certRange.notAfter) > buildDate) {
clockSkew = true;
}
}
let systemDate = formatter.format(new Date());
document.getElementById("wrongSystemTime_systemDate1").textContent = systemDate;
if (clockSkew) {
document.body.classList.add("illustrated", "clockSkewError");
let clockErrTitle = document.getElementById("et_clockSkewError");
let clockErrDesc = document.getElementById("ed_clockSkewError");
// eslint-disable-next-line no-unsanitized/property
document.querySelector(".title-text").textContent = clockErrTitle.textContent;
desc = document.getElementById("errorShortDescText");
document.getElementById("errorShortDesc").style.display = "block";
document.getElementById("certificateErrorReporting").style.display = "none";
if (desc) {
// eslint-disable-next-line no-unsanitized/property
desc.innerHTML = clockErrDesc.innerHTML;
}
let errorPageContainer = document.getElementById("errorPageContainer");
let textContainer = document.getElementById("text-container");
errorPageContainer.style.backgroundPosition = `left top calc(50vh - ${textContainer.clientHeight / 2}px)`;
} else {
let targetElems = document.querySelectorAll("#wrongSystemTime_systemDate2");
for (let elem of targetElems) {
elem.textContent = systemDate;
}
let errDesc = document.getElementById("ed_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE");
let sd = document.getElementById("errorShortDescText");
// eslint-disable-next-line no-unsanitized/property
sd.innerHTML = errDesc.innerHTML;
let span = sd.querySelector(".hostname");
span.textContent = document.location.hostname;
// The secondary description mentions expired certificates explicitly
// and should only be shown if the certificate has actually expired
// instead of being not yet valid.
if (failedCertInfo.errorCodeString == "SEC_ERROR_EXPIRED_CERTIFICATE") {
let cssClass = getCSSClass();
let stsSuffix = cssClass == "badStsCert" ? "_sts" : "";
let errDesc2 = document.getElementById(
`ed2_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE${stsSuffix}`);
let sd2 = document.getElementById("errorShortDescText2");
// eslint-disable-next-line no-unsanitized/property
sd2.innerHTML = errDesc2.innerHTML;
}
if (es) {
// eslint-disable-next-line no-unsanitized/property
es.innerHTML = errWhatToDo.innerHTML;
}
if (est) {
// eslint-disable-next-line no-unsanitized/property
est.textContent = errWhatToDoTitle.textContent;
est.style.fontWeight = "bold";
}
updateContainerPosition();
}
break;
}
// Add slightly more alarming UI unless there are indicators that
// show that the error is harmless or can not be skipped anyway.
let cssClass = getCSSClass();
// Don't alarm users when they can't continue to the website anyway...
if (cssClass != "badStsCert" &&
// Errors in iframes can't be skipped either...
window.parent == window &&
// Also don't bother if it's just the user's clock being off...
!clockSkew &&
// Symantec distrust is likely harmless as well.
failedCertInfo.erroCodeString != "MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED") {
document.body.classList.add("caution");
}
}
function setTechnicalDetailsOnCertError() {
@ -530,7 +770,6 @@ function setTechnicalDetailsOnCertError() {
if (failedCertInfo.isNotValidAtThisTime) {
let notBefore = failedCertInfo.validNotBefore;
let notAfter = failedCertInfo.validNotAfter;
let formatter = new Intl.DateTimeFormat("default");
args = {
hostname: hostString,
};

Просмотреть файл

@ -3034,8 +3034,6 @@ var BrowserOnClick = {
mm.addMessageListener("Browser:ResetSSLPreferences", this);
mm.addMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.addMessageListener("Browser:SSLErrorGoBack", this);
mm.addMessageListener("Browser:PrimeMitm", this);
mm.addMessageListener("Browser:ResetEnterpriseRootsPref", this);
},
uninit() {
@ -3047,8 +3045,6 @@ var BrowserOnClick = {
mm.removeMessageListener("Browser:ResetSSLPreferences", this);
mm.removeMessageListener("Browser:SSLErrorReportTelemetry", this);
mm.removeMessageListener("Browser:SSLErrorGoBack", this);
mm.removeMessageListener("Browser:PrimeMitm", this);
mm.removeMessageListener("Browser:ResetEnterpriseRootsPref", this);
},
receiveMessage(msg) {
@ -3096,76 +3092,9 @@ var BrowserOnClick = {
case "Browser:SSLErrorGoBack":
goBackFromErrorPage();
break;
case "Browser:PrimeMitm":
this.primeMitm(msg.target);
break;
case "Browser:ResetEnterpriseRootsPref":
Services.prefs.clearUserPref("security.enterprise_roots.enabled");
Services.prefs.clearUserPref("security.enterprise_roots.auto-enabled");
break;
}
},
/**
* This function does a canary request to a reliable, maintained endpoint, in
* order to help network code detect a system-wide man-in-the-middle.
*/
primeMitm(browser) {
// If we already have a mitm canary issuer stored, then don't bother with the
// extra request. This will be cleared on every update ping.
if (Services.prefs.getStringPref("security.pki.mitm_canary_issuer", null)) {
return;
}
let url = Services.prefs.getStringPref("security.certerrors.mitm.priming.endpoint");
let request = new XMLHttpRequest({mozAnon: true});
request.open("HEAD", url);
request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
request.addEventListener("error", event => {
// Make sure the user is still on the cert error page.
if (!browser.documentURI.spec.startsWith("about:certerror")) {
return;
}
let secInfo = request.channel.securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
if (secInfo.errorCode != SEC_ERROR_UNKNOWN_ISSUER) {
return;
}
// When we get to this point there's already something deeply wrong, it's very likely
// that there is indeed a system-wide MitM.
if (secInfo.serverCert && secInfo.serverCert.issuerName) {
// Grab the issuer of the certificate used in the exchange and store it so that our
// network-level MitM detection code has a comparison baseline.
Services.prefs.setStringPref("security.pki.mitm_canary_issuer", secInfo.serverCert.issuerName);
// MitM issues are sometimes caused by software not registering their root certs in the
// Firefox root store. We might opt for using third party roots from the system root store.
if (Services.prefs.getBoolPref("security.certerrors.mitm.auto_enable_enterprise_roots")) {
if (!Services.prefs.getBoolPref("security.enterprise_roots.enabled")) {
// Loading enterprise roots happens on a background thread, so wait for import to finish.
BrowserUtils.promiseObserved("psm:enterprise-certs-imported").then(() => {
if (browser.documentURI.spec.startsWith("about:certerror")) {
browser.reload();
}
});
Services.prefs.setBoolPref("security.enterprise_roots.enabled", true);
// Record that this pref was automatically set.
Services.prefs.setBoolPref("security.enterprise_roots.auto-enabled", true);
}
} else {
// Need to reload the page to make sure network code picks up the canary issuer pref.
browser.reload();
}
}
});
request.send(null);
},
onCertError(browser, elementId, isTopFrame, location, securityInfoAsString, frameId) {
let securityInfo;
let cert;
@ -3214,11 +3143,15 @@ var BrowserOnClick = {
securityInfo = getSecurityInfo(securityInfoAsString);
let errorInfo = getDetailedCertErrorInfo(location,
securityInfo);
let clockSkewDifference = Services.prefs.getIntPref("services.settings.clock_skew_seconds", 0);
let settingsLastFetched = Services.prefs.getIntPref("services.settings.last_update_seconds", 0);
let appBuildID = Services.appinfo.appBuildID;
browser.messageManager.sendAsyncMessage("CertErrorDetails", {
code: securityInfo.errorCode,
info: errorInfo,
codeString: securityInfo.errorCodeString,
frameId,
info: errorInfo,
clockSkewDifference,
settingsLastFetched,
appBuildID,
frameId,
});
break;

Просмотреть файл

@ -40,9 +40,7 @@ add_task(async function checkWrongSystemTimeWarning() {
// Pretend that we recently updated our kinto clock skew pref
Services.prefs.setIntPref(PREF_SERVICES_SETTINGS_LAST_FETCHED, Math.floor(Date.now() / 1000));
let formatter = new Services.intl.DateTimeFormat(undefined, {
dateStyle: "long",
});
let formatter = new Intl.DateTimeFormat("default");
// For this test, we want to trick Firefox into believing that
// the local system time (as returned by Date.now()) is wrong.

Просмотреть файл

@ -64,7 +64,7 @@ add_task(async function checkTelemetryClickEvents() {
let loadEvents = await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).content;
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, true).parent;
if (events && events.length) {
events = events.filter(e => e[1] == "security.ui.certerror" && e[2] == "load");
if (events.length == 1 && events[0][5].is_frame == useFrame.toString()) {

Просмотреть файл

@ -8,14 +8,23 @@ var EXPORTED_SYMBOLS = ["AboutNetErrorHandler"];
const {RemotePages} = ChromeUtils.import("resource://gre/modules/remotepagemanager/RemotePageManagerParent.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm");
var AboutNetErrorHandler = {
_inited: false,
_topics: [
"Browser:OpenCaptivePortalPage",
"Browser:PrimeMitm",
"Browser:ResetEnterpriseRootsPref",
"RecordCertErrorLoad",
],
init() {
this._boundReceiveMessage = this.receiveMessage.bind(this);
this.pageListener = new RemotePages(["about:certerror", "about:neterror"]);
this.pageListener.addMessageListener("Browser:OpenCaptivePortalPage", this._boundReceiveMessage);
for (let topic of this._topics) {
this.pageListener.addMessageListener(topic, this._boundReceiveMessage);
}
this._inited = true;
Services.obs.addObserver(this, "captive-portal-login-abort");
@ -27,7 +36,9 @@ var AboutNetErrorHandler = {
return;
}
this.pageListener.removeMessageListener("Browser:OpenCaptivePortalPage", this._boundReceiveMessage);
for (let topic of this._topics) {
this.pageListener.removeMessageListener(topic, this._boundReceiveMessage);
}
this.pageListener.destroy();
Services.obs.removeObserver(this, "captive-portal-login-abort");
@ -50,6 +61,79 @@ var AboutNetErrorHandler = {
case "Browser:OpenCaptivePortalPage":
Services.obs.notifyObservers(null, "ensure-captive-portal-tab");
break;
case "Browser:PrimeMitm":
this.primeMitm(msg.target.browser);
break;
case "Browser:ResetEnterpriseRootsPref":
Services.prefs.clearUserPref("security.enterprise_roots.enabled");
Services.prefs.clearUserPref("security.enterprise_roots.auto-enabled");
break;
case "RecordCertErrorLoad":
Services.telemetry.recordEvent("security.ui.certerror", "load", "aboutcerterror", msg.data.errorCode, {
has_sts: msg.data.has_sts.toString(),
is_frame: msg.data.is_frame.toString(),
});
break;
}
},
/**
* This function does a canary request to a reliable, maintained endpoint, in
* order to help network code detect a system-wide man-in-the-middle.
*/
primeMitm(browser) {
// If we already have a mitm canary issuer stored, then don't bother with the
// extra request. This will be cleared on every update ping.
if (Services.prefs.getStringPref("security.pki.mitm_canary_issuer", null)) {
return;
}
let url = Services.prefs.getStringPref("security.certerrors.mitm.priming.endpoint");
let request = new XMLHttpRequest({mozAnon: true});
request.open("HEAD", url);
request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
request.addEventListener("error", event => {
// Make sure the user is still on the cert error page.
if (!browser.documentURI.spec.startsWith("about:certerror")) {
return;
}
let secInfo = request.channel.securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
if (secInfo.errorCodeString != "SEC_ERROR_UNKNOWN_ISSUER") {
return;
}
// When we get to this point there's already something deeply wrong, it's very likely
// that there is indeed a system-wide MitM.
if (secInfo.serverCert && secInfo.serverCert.issuerName) {
// Grab the issuer of the certificate used in the exchange and store it so that our
// network-level MitM detection code has a comparison baseline.
Services.prefs.setStringPref("security.pki.mitm_canary_issuer", secInfo.serverCert.issuerName);
// MitM issues are sometimes caused by software not registering their root certs in the
// Firefox root store. We might opt for using third party roots from the system root store.
if (Services.prefs.getBoolPref("security.certerrors.mitm.auto_enable_enterprise_roots")) {
if (!Services.prefs.getBoolPref("security.enterprise_roots.enabled")) {
// Loading enterprise roots happens on a background thread, so wait for import to finish.
BrowserUtils.promiseObserved("psm:enterprise-certs-imported").then(() => {
if (browser.documentURI.spec.startsWith("about:certerror")) {
browser.reload();
}
});
Services.prefs.setBoolPref("security.enterprise_roots.enabled", true);
// Record that this pref was automatically set.
Services.prefs.setBoolPref("security.enterprise_roots.auto-enabled", true);
}
} else {
// Need to reload the page to make sure network code picks up the canary issuer pref.
browser.reload();
}
}
});
request.send(null);
},
};

Просмотреть файл

@ -64,3 +64,9 @@ cert-error-not-yet-valid-now = Websites prove their identity via certificates, w
# $error (String) - NSS error code string that specifies type of cert error. e.g. unknown issuer, invalid cert, etc.
cert-error-code-prefix-link = Error code: <a data-l10n-name="error-code-link">{ $error }</a>
# Variables:
# $hostname (String) - Hostname of the website with cert error.
cert-error-symantec-distrust-description = Websites prove their identity via certificates, which are issued by certificate authorities. Most browsers no longer trust certificates issued by GeoTrust, RapidSSL, Symantec, Thawte, and VeriSign. { $hostname } uses a certificate from one of these authorities and so the websites identity cannot be proven.
cert-error-symantec-distrust-admin = You may notify the websites administrator about this problem.

Просмотреть файл

@ -247,10 +247,6 @@ body:not(.neterror) #advancedButton {
display: none;
}
#wrongSystemTimePanel {
display: none;
}
#wrongSystemTimeWithoutReferencePanel {
display: none;
}

Просмотреть файл

@ -0,0 +1,37 @@
# coding=utf8
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
from __future__ import absolute_import
import fluent.syntax.ast as FTL
from fluent.migrate.helpers import transforms_from
from fluent.migrate.helpers import VARIABLE_REFERENCE
from fluent.migrate import COPY, REPLACE
def migrate(ctx):
"""Bug 1552333 - Migrate strings from pipnss.properties to aboutCertError.ftl"""
ctx.add_transforms(
'browser/browser/aboutCertError.ftl',
'browser/browser/aboutCertError.ftl',
transforms_from(
"""
cert-error-symantec-distrust-admin = { COPY(from_path, "certErrorSymantecDistrustAdministrator") }
""", from_path="security/manager/chrome/pipnss/pipnss.properties"))
ctx.add_transforms(
'browser/browser/aboutCertError.ftl',
'browser/browser/aboutCertError.ftl',
[
FTL.Message(
id=FTL.Identifier('cert-error-symantec-distrust-description'),
value=REPLACE(
'security/manager/chrome/pipnss/pipnss.properties',
'certErrorSymantecDistrustDescription1',
{
"%1$S": VARIABLE_REFERENCE("hostname"),
},
normalize_printf=True
),
),
]
)

Просмотреть файл

@ -285,8 +285,6 @@ certErrorMitM2=%S is backed by the non-profit Mozilla, which administers a compl
# LOCALIZATION NOTE (certErrorMitM3): %S is brandShortName
certErrorMitM3=%S uses the Mozilla CA store to verify that a connection is secure, rather than certificates supplied by the users operating system. So, if an antivirus program or a network is intercepting a connection with a security certificate issued by a CA that is not in the Mozilla CA store, the connection is considered unsafe.
# LOCALIZATION NOTE (certErrorSymantecDistrustDescription1): %S will be replaced by the domain for which the certificate is valid.
certErrorSymantecDistrustDescription1=Websites prove their identity via certificates, which are issued by certificate authorities. Most browsers no longer trust certificates issued by GeoTrust, RapidSSL, Symantec, Thawte, and VeriSign. %S uses a certificate from one of these authorities and so the websites identity cannot be proven.
certErrorSymantecDistrustAdministrator=You may notify the websites administrator about this problem.
# LOCALIZATION NOTE (certErrorCodePrefix3): %S is replaced by the error code.

Просмотреть файл

@ -25,6 +25,11 @@ ChromeUtils.defineModuleGetter(this, "UpdateUtils",
*/
let RPMAccessManager = {
accessMap: {
"about:certerror": {
"getFormatURLPref": ["app.support.baseURL"],
"getBoolPref": ["security.certerrors.mitm.priming.enabled",
"security.enterprise_roots.auto-enabled"],
},
"about:privatebrowsing": {
// "sendAsyncMessage": handled within AboutPrivateBrowsingHandler.jsm
"getFormatURLPref": ["app.support.baseURL"],
@ -41,7 +46,11 @@ let RPMAccessManager = {
if (!aPrincipal || !aPrincipal.URI) {
return false;
}
let uri = aPrincipal.URI.asciiSpec;
if (uri.startsWith("about:certerror")) {
uri = "about:certerror";
}
// check if there is an entry for that requestying URI in the accessMap;
// if not, deny access.

Просмотреть файл

@ -1052,7 +1052,7 @@ security.ui.certerror:
- rtestard@mozilla.com
- seceng-telemetry@mozilla.com
release_channel_collection: opt-out
record_in_processes: ["content"]
record_in_processes: ["main", "content"]
products:
- firefox
extra_keys: