Bug 1201437 - Add new WebProgress state flag for user-overridden cert. r=keeler
authorNihanth Subramanya <nhnt11@gmail.com>
Wed, 24 Feb 2016 22:46:52 -0800
changeset 285551 4dd771bf8c9814479f87f30e17daaa21e3f5bdfb
parent 285550 dbba65699809fcd30759a0c3b521651d2993fa55
child 285552 9e3ebc1164544108b203aa083cf55770eef5f164
push id72403
push usercbook@mozilla.com
push dateThu, 25 Feb 2016 10:59:17 +0000
treeherdermozilla-inbound@3b913f81cb98 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs1201437
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1201437 - Add new WebProgress state flag for user-overridden cert. r=keeler MozReview-Commit-ID: cvBYSZykK0
security/manager/ssl/nsNSSCallbacks.cpp
security/manager/ssl/nsNSSComponent.cpp
security/manager/ssl/nsSecureBrowserUIImpl.cpp
security/manager/ssl/nsSecureBrowserUIImpl.h
uriloader/base/nsIWebProgressListener.idl
--- a/security/manager/ssl/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/nsNSSCallbacks.cpp
@@ -1,31 +1,33 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsNSSCallbacks.h"
-#include "pkix/pkixtypes.h"
+
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
+#include "nsContentUtils.h"
+#include "nsICertOverrideService.h"
+#include "nsIHttpChannelInternal.h"
+#include "nsIPrompt.h"
+#include "nsISupportsPriority.h"
+#include "nsITokenDialogs.h"
+#include "nsIUploadChannel.h"
+#include "nsIWebProgressListener.h"
+#include "nsNetUtil.h"
 #include "nsNSSComponent.h"
 #include "nsNSSIOLayer.h"
-#include "nsIWebProgressListener.h"
 #include "nsProtectedAuthThread.h"
-#include "nsITokenDialogs.h"
-#include "nsIUploadChannel.h"
-#include "nsIPrompt.h"
 #include "nsProxyRelease.h"
+#include "pkix/pkixtypes.h"
 #include "PSMRunnable.h"
-#include "nsContentUtils.h"
-#include "nsIHttpChannelInternal.h"
-#include "nsISupportsPriority.h"
-#include "nsNetUtil.h"
 #include "SharedSSLState.h"
 #include "ssl.h"
 #include "sslproto.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 extern PRLogModuleInfo* gPIPNSSLog;
@@ -1230,16 +1232,27 @@ void HandshakeCallback(PRFileDesc* fd, v
                                         &siteSupportsSafeRenego);
   MOZ_ASSERT(rv == SECSuccess);
   if (rv != SECSuccess) {
     siteSupportsSafeRenego = false;
   }
   bool renegotiationUnsafe = !siteSupportsSafeRenego &&
                              ioLayerHelpers.treatUnsafeNegotiationAsBroken();
 
+
+  /* Set the SSL Status information */
+  RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
+  if (!status) {
+    status = new nsSSLStatus();
+    infoObject->SetSSLStatus(status);
+  }
+
+  RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject,
+                                                             status);
+
   uint32_t state;
   if (usesWeakCipher || renegotiationUnsafe) {
     state = nsIWebProgressListener::STATE_IS_BROKEN;
     if (usesWeakCipher) {
       state |= nsIWebProgressListener::STATE_USES_WEAK_CRYPTO;
     }
   } else {
     state = nsIWebProgressListener::STATE_IS_SECURE |
@@ -1247,16 +1260,49 @@ void HandshakeCallback(PRFileDesc* fd, v
     SSLVersionRange defVersion;
     rv = SSL_VersionRangeGetDefault(ssl_variant_stream, &defVersion);
     if (rv == SECSuccess && versions.max >= defVersion.max) {
       // we know this site no longer requires a weak cipher
       ioLayerHelpers.removeInsecureFallbackSite(infoObject->GetHostName(),
                                                 infoObject->GetPort());
     }
   }
+
+  if (status->HasServerCert()) {
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+           ("HandshakeCallback KEEPING existing cert\n"));
+  } else {
+    ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
+    RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(serverCert.get()));
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
+           ("HandshakeCallback using NEW cert %p\n", nssc.get()));
+    status->SetServerCert(nssc, nsNSSCertificate::ev_status_unknown);
+  }
+
+  nsCOMPtr<nsICertOverrideService> overrideService =
+      do_GetService(NS_CERTOVERRIDE_CONTRACTID);
+
+  if (overrideService) {
+    bool haveOverride;
+    uint32_t overrideBits = 0; // Unused.
+    bool isTemporaryOverride; // Unused.
+    const nsACString& hostString(infoObject->GetHostName());
+    const int32_t port(infoObject->GetPort());
+    nsCOMPtr<nsIX509Cert> cert;
+    status->GetServerCert(getter_AddRefs(cert));
+    nsresult nsrv = overrideService->HasMatchingOverride(hostString, port,
+                                                         cert,
+                                                         &overrideBits,
+                                                         &isTemporaryOverride,
+                                                         &haveOverride);
+    if (NS_SUCCEEDED(nsrv) && haveOverride) {
+      state |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
+    }
+  }
+
   infoObject->SetSecurityState(state);
 
   // XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
   // we should set a flag on the channel that higher (UI) level code can check
   // to log the warning. In particular, these warnings should go to the web
   // console instead of to the error console. Also, the warning is not
   // localized.
   if (!siteSupportsSafeRenego) {
@@ -1265,32 +1311,11 @@ void HandshakeCallback(PRFileDesc* fd, v
 
     nsAutoString msg;
     msg.Append(NS_ConvertASCIItoUTF16(hostName));
     msg.AppendLiteral(" : server does not support RFC 5746, see CVE-2009-3555");
 
     nsContentUtils::LogSimpleConsoleError(msg, "SSL");
   }
 
-  /* Set the SSL Status information */
-  RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
-  if (!status) {
-    status = new nsSSLStatus();
-    infoObject->SetSSLStatus(status);
-  }
-
-  RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject,
-                                                             status);
-
-  if (status->HasServerCert()) {
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-           ("HandshakeCallback KEEPING existing cert\n"));
-  } else {
-    ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
-    RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(serverCert.get()));
-    MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
-           ("HandshakeCallback using NEW cert %p\n", nssc.get()));
-    status->SetServerCert(nssc, nsNSSCertificate::ev_status_unknown);
-  }
-
   infoObject->NoteTimeUntilReady();
   infoObject->SetHandshakeCompleted();
 }
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -1112,16 +1112,24 @@ nsNSSComponent::InitializeNSS()
   // Initialize the site security service
   nsCOMPtr<nsISiteSecurityService> sssService =
     do_GetService(NS_SSSERVICE_CONTRACTID);
   if (!sssService) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Cannot initialize site security service\n"));
     return NS_ERROR_FAILURE;
   }
 
+  // Initialize the cert override service
+  nsCOMPtr<nsICertOverrideService> coService =
+    do_GetService(NS_CERTOVERRIDE_CONTRACTID);
+  if (!coService) {
+    MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Cannot initialize cert override service\n"));
+    return NS_ERROR_FAILURE;
+  }
+
   if (PK11_IsFIPS()) {
     Telemetry::Accumulate(Telemetry::FIPS_ENABLED, true);
   }
 
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("NSS Initialization done\n"));
   return NS_OK;
 }
 
--- a/security/manager/ssl/nsSecureBrowserUIImpl.cpp
+++ b/security/manager/ssl/nsSecureBrowserUIImpl.cpp
@@ -102,16 +102,17 @@ nsSecureBrowserUIImpl::nsSecureBrowserUI
   : mNotifiedSecurityState(lis_no_security)
   , mNotifiedToplevelIsEV(false)
   , mNewToplevelSecurityState(STATE_IS_INSECURE)
   , mNewToplevelIsEV(false)
   , mNewToplevelSecurityStateKnown(true)
   , mIsViewSource(false)
   , mSubRequestsBrokenSecurity(0)
   , mSubRequestsNoSecurity(0)
+  , mCertUserOverridden(false)
   , mRestoreSubrequests(false)
   , mOnLocationChangeSeen(false)
 #ifdef DEBUG
   , mOnStateLocationChangeReentranceDetection(0)
 #endif
   , mTransferringRequests(&gMapOps, sizeof(RequestHashEntry))
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -228,16 +229,20 @@ nsSecureBrowserUIImpl::MapInternalToExte
     case lis_no_security:
       *aState = STATE_IS_INSECURE;
       break;
   }
 
   if (ev && (*aState & STATE_IS_SECURE))
     *aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
 
+  if (mCertUserOverridden && (*aState & STATE_IS_SECURE)) {
+    *aState |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
+  }
+
   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
   if (!docShell)
     return NS_OK;
 
   // For content docShell's, the mixed content security state is set on the root docShell.
   if (docShell->ItemType() == nsIDocShellTreeItem::typeContent) {
     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem(do_QueryInterface(docShell));
     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
@@ -255,16 +260,19 @@ nsSecureBrowserUIImpl::MapInternalToExte
       !docShell->GetHasMixedActiveContentLoaded() &&
       !docShell->GetHasMixedDisplayContentLoaded() &&
       !docShell->GetHasMixedActiveContentBlocked() &&
       !docShell->GetHasMixedDisplayContentBlocked()) {
     *aState = STATE_IS_SECURE;
     if (ev) {
       *aState |= nsIWebProgressListener::STATE_IDENTITY_EV_TOPLEVEL;
     }
+    if (mCertUserOverridden) {
+      *aState |= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
+    }
   }
   // * If so, the state should be broken or insecure; overriding the previous
   // state set by the lock parameter.
   uint32_t tempState = STATE_IS_BROKEN;
   if (lock == lis_no_security) {
       // this is to ensure that http: pages with mixed content in nested
       // iframes don't get marked as broken instead of insecure
       tempState = STATE_IS_INSECURE;
@@ -788,16 +796,21 @@ nsSecureBrowserUIImpl::OnStateChange(nsI
     f -= nsIWebProgressListener::STATE_IS_SECURE;
     info.AppendLiteral("IS_SECURE ");
   }
   if (f & nsIWebProgressListener::STATE_SECURE_HIGH)
   {
     f -= nsIWebProgressListener::STATE_SECURE_HIGH;
     info.AppendLiteral("SECURE_HIGH ");
   }
+  if (f & nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN)
+  {
+    f -= nsIWebProgressListener::STATE_CERT_USER_OVERRIDDEN;
+    info.AppendLiteral("STATE_CERT_USER_OVERRIDDEN ");
+  }
   if (f & nsIWebProgressListener::STATE_RESTORING)
   {
     f -= nsIWebProgressListener::STATE_RESTORING;
     info.AppendLiteral("STATE_RESTORING ");
   }
 
   if (f > 0)
   {
@@ -1126,16 +1139,19 @@ nsSecureBrowserUIImpl::UpdateSecuritySta
       newSecurityState = lis_high_security;
     }
   }
 
   if (mNewToplevelSecurityState & STATE_IS_BROKEN) {
     newSecurityState = lis_broken_security;
   }
 
+  mCertUserOverridden =
+    mNewToplevelSecurityState & STATE_CERT_USER_OVERRIDDEN;
+
   MOZ_LOG(gSecureDocLog, LogLevel::Debug,
          ("SecureUI:%p: UpdateSecurityState:  old-new  %d - %d\n", this,
           mNotifiedSecurityState, newSecurityState));
 
   bool flagsChanged = false;
   if (mNotifiedSecurityState != newSecurityState) {
     // Something changed since the last time.
     flagsChanged = true;
--- a/security/manager/ssl/nsSecureBrowserUIImpl.h
+++ b/security/manager/ssl/nsSecureBrowserUIImpl.h
@@ -69,16 +69,17 @@ protected:
   uint32_t mNewToplevelSecurityState;
   bool mNewToplevelIsEV;
   bool mNewToplevelSecurityStateKnown;
   bool mIsViewSource;
 
   int32_t mDocumentRequestsInProgress;
   int32_t mSubRequestsBrokenSecurity;
   int32_t mSubRequestsNoSecurity;
+  bool mCertUserOverridden;
   bool mRestoreSubrequests;
   bool mOnLocationChangeSeen;
 #ifdef DEBUG
   mozilla::Atomic<int32_t> mOnStateLocationChangeReentranceDetection;
 #endif
 
   static already_AddRefed<nsISupports> ExtractSecurityInfo(nsIRequest* aRequest);
   nsresult MapInternalToExternalState(uint32_t* aState, lockIconState lock, bool ev);
--- a/uriloader/base/nsIWebProgressListener.idl
+++ b/uriloader/base/nsIWebProgressListener.idl
@@ -257,19 +257,23 @@ interface nsIWebProgressListener : nsISu
     *
     * These flags describe the reason of the broken state.
     *
     * STATE_USES_SSL_3
     *   The topmost document uses SSL 3.0.
     *
     * STATE_USES_WEAK_CRYPTO
     *   The topmost document uses a weak cipher suite such as RC4.
+    *
+    * STATE_CERT_USER_OVERRIDDEN
+    *   The user has added a security exception for the site.
     */
   const unsigned long STATE_USES_SSL_3                = 0x01000000;
   const unsigned long STATE_USES_WEAK_CRYPTO          = 0x02000000;
+  const unsigned long STATE_CERT_USER_OVERRIDDEN      = 0x04000000;
 
   /**
    * Notification indicating the state has changed for one of the requests
    * associated with aWebProgress.
    *
    * @param aWebProgress
    *        The nsIWebProgress instance that fired the notification
    * @param aRequest