Bug 1409259 - Add a console warning for soon-to-be-distrusted roots r=keeler,ttaubert

This patch adds a new diagnostic status flag to nsIWebProgressListener,
STATE_CERT_DISTRUST_IMMINENT, which indicates that the certificate chain is
going to change validity due to an upcoming distrust event. The first of
these events is this bug, affecting various roots from Symantec.

The STATE_CERT_DISTRUST_IMMINENT flag is set by nsNSSCallbacks and passed,
via nsSecureBrowserUIImpl, to browser.js where it is used to alert the console.

Adding this sort of diagnostic printing to be accessible to browser.js is a
long-desired goal, as future functionality can start doing more decision-making
there. We may, for example, also want to degrade the lock icon, which will be
straightforward with this flag.

This commit does not implement the IsCertificateDistrustImminent method. That is
follow-on work.

MozReview-Commit-ID: 75IOdc24XIV

--HG--
extra : rebase_source : e6a95d0be65f667eff0b131274272f0df91f8732
This commit is contained in:
J.C. Jones 2017-10-18 22:29:42 -07:00
Родитель ce24b2607a
Коммит 0e002bccbd
5 изменённых файлов: 123 добавлений и 0 удалений

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

@ -7199,6 +7199,10 @@ var gIdentityHandler = {
return this._state & Ci.nsIWebProgressListener.STATE_CERT_USER_OVERRIDDEN;
},
get _isCertDistrustImminent() {
return this._state & Ci.nsIWebProgressListener.STATE_CERT_DISTRUST_IMMINENT;
},
get _hasInsecureLoginForms() {
// checks if the page has been flagged for an insecure login. Also checks
// if the pref to degrade the UI is set to true
@ -7450,6 +7454,19 @@ var gIdentityHandler = {
// we receive a new security state on the existing page (i.e. from a
// subframe). If the user opened the popup and looks at the provided
// information we don't want to suddenly change the panel contents.
// Finally, if there are warnings to issue, issue them
if (this._isCertDistrustImminent) {
let consoleMsg = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError);
let windowId = gBrowser.selectedBrowser.innerWindowID;
let message = gBrowserBundle.GetStringFromName("certImminentDistrust.message");
// Use uri.prePath instead of initWithSourceURI() so that these can be
// de-duplicated on the scheme+host+port combination.
consoleMsg.initWithWindowID(message, uri.prePath, null, 0, 0,
Ci.nsIScriptError.warningFlag, "SSL",
windowId);
Services.console.logMessage(consoleMsg);
}
},
/**

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

@ -915,3 +915,8 @@ permissions.remove.tooltip = Clear this permission and ask again
# e.g.: "48.0.2 (32-bit) <What's new>" or "51.0a1 (2016-09-05) (64-bit)".
aboutDialog.architecture.sixtyFourBit = 64-bit
aboutDialog.architecture.thirtyTwoBit = 32-bit
# LOCALIZATION NOTE (certImminentDistrust.message):
# Shown in the browser console when visiting a website that is trusted today,
# but won't be in the future unless the site operator makes a change.
certImminentDistrust.message = The security certificate in use on this web site will no longer be trusted in a future release of Firefox. For more information, visit https://wiki.mozilla.org/CA/Upcoming_Distrust_Actions

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

@ -34,6 +34,11 @@
#include "ssl.h"
#include "sslproto.h"
#include "TrustOverrideUtils.h"
#include "TrustOverride-SymantecData.inc"
#include "TrustOverride-AppleGoogleData.inc"
using namespace mozilla;
using namespace mozilla::pkix;
using namespace mozilla::psm;
@ -1260,6 +1265,72 @@ DetermineEVAndCTStatusAndSetNewCert(RefPtr<nsSSLStatus> sslStatus,
}
}
static nsresult
IsCertificateDistrustImminent(nsIX509CertList* aCertList,
/* out */ bool& aResult) {
if (!aCertList) {
return NS_ERROR_INVALID_POINTER;
}
nsCOMPtr<nsIX509Cert> rootCert;
nsCOMPtr<nsIX509CertList> intCerts;
nsCOMPtr<nsIX509Cert> eeCert;
RefPtr<nsNSSCertList> certList = aCertList->GetCertList();
nsresult rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
if (NS_FAILED(rv)) {
return rv;
}
// We need to verify the age of the end entity
nsCOMPtr<nsIX509CertValidity> validity;
rv = eeCert->GetValidity(getter_AddRefs(validity));
if (NS_FAILED(rv)) {
return rv;
}
PRTime notBefore;
rv = validity->GetNotBefore(&notBefore);
if (NS_FAILED(rv)) {
return rv;
}
// PRTime is microseconds since the epoch, whereas JS time is milliseconds.
// (new Date("2016-06-01T00:00:00Z")).getTime() * 1000
static const PRTime JUNE_1_2016 = 1464739200000000;
// If the end entity's notBefore date is after 2016-06-01, this algorithm
// doesn't apply, so exit false before we do any iterating
if (notBefore >= JUNE_1_2016) {
aResult = false;
return NS_OK;
}
// If the root is not one of the Symantec roots, exit false
if (!CertDNIsInList(rootCert->GetCert(), RootSymantecDNs)) {
aResult = false;
return NS_OK;
}
// Look for one of the intermediates to be in the whitelist
bool foundInWhitelist = false;
RefPtr<nsNSSCertList> intCertList = intCerts->GetCertList();
intCertList->ForEachCertificateInChain(
[&foundInWhitelist] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore,
/* out */ bool& aContinue) {
if (CertDNIsInList(aCert->GetCert(), RootAppleAndGoogleDNs)) {
foundInWhitelist = true;
aContinue = false;
}
return NS_OK;
});
// If this chain did not match the whitelist, exit true
aResult = !foundInWhitelist;
return NS_OK;
}
void HandshakeCallback(PRFileDesc* fd, void* client_data) {
nsNSSShutDownPreventionLock locker;
SECStatus rv;
@ -1411,6 +1482,18 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) {
DetermineEVAndCTStatusAndSetNewCert(status, fd, infoObject);
}
nsCOMPtr<nsIX509CertList> succeededCertChain;
// This always returns NS_OK, but the list could be empty. This is a
// best-effort check for now. Bug 731478 will reduce the incidence of empty
// succeeded cert chains through better caching.
Unused << status->GetSucceededCertChain(getter_AddRefs(succeededCertChain));
bool distrustImminent;
nsresult srv = IsCertificateDistrustImminent(succeededCertChain,
distrustImminent);
if (NS_SUCCEEDED(srv) && distrustImminent) {
state |= nsIWebProgressListener::STATE_CERT_DISTRUST_IMMINENT;
}
bool domainMismatch;
bool untrusted;
bool notValidAtThisTime;

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

@ -269,6 +269,12 @@ nsSecureBrowserUIImpl::MapInternalToExternalState(uint32_t* aState, lockIconStat
if (docShell->GetHasTrackingContentLoaded())
*aState |= nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT;
// Copy forward any diagnostic flags for downstream use (e.g., warnings)
if (mNewToplevelSecurityStateKnown &&
mNewToplevelSecurityState & STATE_CERT_DISTRUST_IMMINENT) {
*aState |= nsIWebProgressListener::STATE_CERT_DISTRUST_IMMINENT;
}
return NS_OK;
}

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

@ -223,6 +223,18 @@ interface nsIWebProgressListener : nsISupports
const unsigned long STATE_LOADED_TRACKING_CONTENT = 0x00002000;
const unsigned long STATE_BLOCKED_UNSAFE_CONTENT = 0x00004000;
/**
* Diagnostic flags
*
* May be set in addition to other security state flags to indicate that
* some state is countered that deserves a warning or error, but does not
* change the top level security state of the connection.
*
* STATE_CERT_DISTRUST_IMMINENT
* The certificate in use will be distrusted in the near future.
*/
const unsigned long STATE_CERT_DISTRUST_IMMINENT = 0x00008000;
/**
* Security Strength Flags
*