Commit c3775a66 authored by Richard Pospesel's avatar Richard Pospesel Committed by Georg Koppen
Browse files

Bug 23247: Communicating security expectations for .onion

Encrypting pages hosted on Onion Services with SSL/TLS is redundant
(in terms of hiding content) as all traffic within the Tor network is
already fully encrypted.  Therefore, serving HTTP pages from an Onion
Service is more or less fine.

Prior to this patch, Tor Browser would mostly treat pages delivered
via Onion Services as well as pages delivered in the ordinary fashion
over the internet in the same way.  This created some inconsistencies
in behaviour and misinformation presented to the user relating to the
security of pages delivered via Onion Services:

 - HTTP Onion Service pages did not have any 'lock' icon indicating
   the site was secure
 - HTTP Onion Service pages would be marked as unencrypted in the Page
   Info screen
 - Mixed-mode content restrictions did not apply to HTTP Onion Service
   pages embedding Non-Onion HTTP content

This patch fixes the above issues, and also adds several new 'Onion'
icons to the mix to indicate all of the various permutations of Onion
Services hosted HTTP or HTTPS pages with HTTP or HTTPS content.

Strings for Onion Service Page Info page are pulled from Torbutton's
localization strings.
parent 2ba0f409
Loading
Loading
Loading
Loading
+42 −24
Original line number Diff line number Diff line
@@ -7517,6 +7517,10 @@ var gIdentityHandler = {
           Services.prefs.getBoolPref("security.insecure_password.ui.enabled");
  },

  get _uriIsOnionHost() {
    return this._uriHasHost ? this._uri.host.toLowerCase().endsWith(".onion") : false;
  },

  // smart getters
  get _identityPopup() {
    delete this._identityPopup;
@@ -7816,12 +7820,12 @@ var gIdentityHandler = {
  get pointerlockFsWarningClassName() {
    // Note that the fullscreen warning does not handle _isSecureInternalUI.
    if (this._uriHasHost && this._isEV) {
      return "verifiedIdentity";
      return this._uriIsOnionHost ? "onionVerifiedIdentity" : "verifiedIdentity";
    }
    if (this._uriHasHost && this._isSecure) {
      return "verifiedDomain";
      return this._uriIsOnionHost ? "onionVerifiedDomain" : "verifiedDomain";
    }
    return "unknownIdentity";
    return this._uriIsOnionHost ? "onionUnknownIdentity" : "unknownIdentity";
  },

  /**
@@ -7842,9 +7846,10 @@ var gIdentityHandler = {
      let brandBundle = document.getElementById("bundle_brand");
      icon_label = brandBundle.getString("brandShorterName");
    } else if (this._uriHasHost && this._isEV) {
      this._identityBox.className = "verifiedIdentity";
      let uriIsOnionHost = this._uriIsOnionHost;
      this._identityBox.className = uriIsOnionHost ? "onionVerifiedIdentity" : "verifiedIdentity";
      if (this._isMixedActiveContentBlocked) {
        this._identityBox.classList.add("mixedActiveBlocked");
        this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveBlocked" : "mixedActiveBlocked");
      }

      if (!this._isCertUserOverridden) {
@@ -7870,10 +7875,17 @@ var gIdentityHandler = {
      let extensionName = this._pageExtensionPolicy.name;
      icon_label = gNavigatorBundle.getFormattedString(
        "identity.extension.label", [extensionName]);
    } else if (this._uriHasHost && this._isSecure) {
    // _isSecure implicitly includes onion services, which may not have an SSL certificate
    } else if (this._uriHasHost && this._isSecure && this._sslStatus != null) {
      let uriIsOnionHost = this._uriIsOnionHost;
      if (uriIsOnionHost) {
        this._identityBox.className = this._sslStatus.serverCert.isSelfSigned ? "onionSelfSigned" : "onionVerifiedDomain";
      } else {
        this._identityBox.className = "verifiedDomain";
      }

      if (this._isMixedActiveContentBlocked) {
        this._identityBox.classList.add("mixedActiveBlocked");
        this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveBlocked" : "mixedActiveBlocked");
      }
      if (!this._isCertUserOverridden) {
        // It's a normal cert, verifier is the CA Org.
@@ -7888,19 +7900,21 @@ var gIdentityHandler = {
        // For net errors we should not show notSecure as it's likely confusing
      this._identityBox.className = "unknownIdentity";
    } else {
      let uriIsOnionHost = this._uriIsOnionHost;
      if (this._isBroken) {
        this._identityBox.className = "unknownIdentity";
        this._identityBox.className = uriIsOnionHost ? "onionUnknownIdentity" : "unknownIdentity";

        if (this._isMixedActiveContentLoaded) {
          this._identityBox.classList.add("mixedActiveContent");
          this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveContent" : "mixedActiveContent");
        } else if (this._isMixedActiveContentBlocked) {
          this._identityBox.classList.add("mixedDisplayContentLoadedActiveBlocked");
          this._identityBox.classList.add(uriIsOnionHost ? "onionMixedDisplayContentLoadedActiveBlocked" : "mixedDisplayContentLoadedActiveBlocked");
        } else if (this._isMixedPassiveContentLoaded) {
          this._identityBox.classList.add("mixedDisplayContent");
          this._identityBox.classList.add(uriIsOnionHost ? "onionMixedDisplayContent" : "mixedDisplayContent");
        } else {
          this._identityBox.classList.add("weakCipher");
        }
      } else {
        if (!uriIsOnionHost) {
          let warnOnInsecure = Services.prefs.getBoolPref("security.insecure_connection_icon.enabled") ||
                               (Services.prefs.getBoolPref("security.insecure_connection_icon.pbmode.enabled") &&
                               PrivateBrowsingUtils.isWindowPrivate(window));
@@ -7914,6 +7928,10 @@ var gIdentityHandler = {
            icon_label = gNavigatorBundle.getString("identity.notSecure.label");
            this._identityBox.classList.add("notSecureText");
          }
        // http onion is secure
        } else {
          this._identityBox.className = "onionUnknownIdentity";
        }
      }
      if (this._hasInsecureLoginForms) {
        // Insecure login forms can only be present on "unknown identity"
+47 −10
Original line number Diff line number Diff line
@@ -12,6 +12,10 @@ ChromeUtils.defineModuleGetter(this, "LoginHelper",
ChromeUtils.defineModuleGetter(this, "PluralForm",
                               "resource://gre/modules/PluralForm.jsm");

XPCOMUtils.defineLazyGetter(this, "gTorButtonBundle", function() {
  return Services.strings.createBundle("chrome://torbutton/locale/torbutton.properties");
});

var security = {
  init(uri, windowInfo) {
    this.uri = uri;
@@ -48,6 +52,8 @@ var security = {
      (ui.state & Ci.nsIWebProgressListener.STATE_IS_INSECURE);
    var isEV =
      (ui.state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL);
    var isOnion = hostName.endsWith(".onion");

    ui.QueryInterface(nsISSLStatusProvider);
    var status = ui.SSLStatus;

@@ -65,6 +71,7 @@ var security = {
        isBroken,
        isMixed,
        isEV,
        isOnion,
        cert,
        certificateTransparency: undefined
      };
@@ -121,6 +128,7 @@ var security = {
      isBroken,
      isMixed,
      isEV,
      isOnion,
      cert: null,
      certificateTransparency: null
    };
@@ -257,20 +265,49 @@ function securityOnLoad(uri, windowInfo) {
    }
    msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
  } else if (info.encryptionStrength > 0) {
    if (!info.isOnion) {
      hdr = pkiBundle.getFormattedString("pageInfo_EncryptionWithBitsAndProtocol",
                                         [info.encryptionAlgorithm,
                                          info.encryptionStrength + "",
                                          info.version]);
    } else {
      try {
        hdr = gTorButtonBundle.formatStringFromName("pageInfo_OnionEncryptionWithBitsAndProtocol",
                                         [info.encryptionAlgorithm,
                                          info.encryptionStrength + "",
                                          info.version], 3);
      } catch(err) {
        hdr = "Connection Encrypted (Onion Service, "
               + info.encryptionAlgorithm
               + ", "
               + info.encryptionStrength
               + " bit keys, "
               + info.version
               + ")";
      }
    }
    msg1 = pkiBundle.getString("pageInfo_Privacy_Encrypted1");
    msg2 = pkiBundle.getString("pageInfo_Privacy_Encrypted2");
    security._cert = info.cert;
  } else {
    if (!info.isOnion) {
      hdr = pkiBundle.getString("pageInfo_NoEncryption");
    if (info.hostName != null)
      if (info.hostName != null) {
        msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]);
    else
      } else {
        msg1 = pkiBundle.getString("pageInfo_Privacy_None4");
      }
      msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
    } else {
      try {
        hdr = gTorButtonBundle.GetStringFromName("pageInfo_OnionEncryption");
      } catch (err) {
        hdr = "Connection Encrypted (Onion Service)";
      }

      msg1 = pkiBundle.getString("pageInfo_Privacy_Encrypted1");
      msg2 = pkiBundle.getString("pageInfo_Privacy_Encrypted2");
    }
  }
  setText("security-technical-shortform", hdr);
  setText("security-technical-longform1", msg1);
+20 −0
Original line number Diff line number Diff line
@@ -200,6 +200,26 @@
  visibility: visible;
}

#urlbar[pageproxystate="valid"] > #identity-box.onionUnknownIdentity > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.onionSelfSigned > #connection-icon {
  list-style-image: url(chrome://browser/skin/onion.svg);
  visibility: visible;
}

#urlbar[pageproxystate="valid"] > #identity-box.onionVerifiedDomain > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.onionVerifiedIdentity > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.onionMixedActiveBlocked > #connection-icon {
  list-style-image: url(chrome://browser/skin/onion-lock.svg);
  visibility: visible;
}

#urlbar[pageproxystate="valid"] > #identity-box.onionMixedActiveContent > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.onionMixedDisplayContentLoadedActiveBlocked > #connection-icon,
#urlbar[pageproxystate="valid"] > #identity-box.onionMixedDisplayContent > #connection-icon {
  list-style-image: url(chrome://browser/skin/onion-disabled.svg);
  visibility: visible;
}

#identity-box.extensionPage > #extension-icon {
  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.svg);
  visibility: visible;
+9 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>onion-disabled</title>
    <defs></defs>
    <g id="onion-disabled" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <path d="M3.55670557,13.5290809 C2.58943965,12.7067569 2,11.5773827 2,10.2383803 C2,8.40140797 3.11044937,6.84614642 4.80245393,5.95790561 C4.86922061,5.92314081 4.937062,5.88953483 5.00557508,5.85697179 C5.34048317,5.68140952 5.95495153,5.31464081 6.18735866,4.8796172 C6.261514,4.74090562 6.26057363,4.55305979 6.20885297,4.4070476 C6.11172559,4.13310092 5.57517408,3.53792744 5.57517408,3.53792744 L6.39988357,3 L7.47070238,3.38224206 C7.23186151,2.5028722 6.97233174,1.62308364 8.87366696,4.4408921e-16 L8.87366696,0.000113687544 C8.14572562,0.965320936 8.77600936,1.33867083 8.69392696,2.02329722 C9.36752565,0.933374736 10.7903253,0.789787368 11.8884333,0.334923505 C10.6431583,1.59850841 9.72300609,3.05795044 8.87524898,3.88361241 L9.6358507,4.15511863 C9.6358507,4.15511863 9.27501511,4.42489353 9.52743882,4.95911272 C9.65035936,5.21926936 9.85710767,5.38741514 10.0560643,5.49588134 C10.2394376,5.55069385 10.4187806,5.61269109 10.5936905,5.68164129 C10.7858529,5.7574053 10.9723418,5.84145128 11.1524919,5.93329454 L3.55670557,13.5290809 Z M5.3590214,14.5551922 L12.7674177,7.1467959 C13.5406039,7.99044704 14,9.05632625 14,10.2383803 C14,13.0968586 11.3137496,15 8,15 C7.05229776,15 6.15591919,14.8443406 5.3590214,14.5551922 Z" id="Combined-Shape" fill="#4A4A4A" fill-rule="nonzero"></path>
        <path d="M13.7928932,1.29289322 C14.1834175,0.902368927 14.8165825,0.902368927 15.2071068,1.29289322 C15.5976311,1.68341751 15.5976311,2.31658249 15.2071068,2.70710678 L2.70710678,15.2071068 C2.31658249,15.5976311 1.68341751,15.5976311 1.29289322,15.2071068 C0.902368927,14.8165825 0.902368927,14.1834175 1.29289322,13.7928932 L13.7928932,1.29289322 Z" id="Line-2" fill="#D92D21" fill-rule="nonzero"></path>
    </g>
</svg>
+9 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>onion+lock</title>
    <defs></defs>
    <g id="onion+lock" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <path d="M6.12228848,14.9544711 C3.22461281,14.6498012 1,12.8396709 1,10.2383803 C1,8.40140797 2.11044937,6.84614642 3.80245393,5.95790561 C3.86922061,5.92314081 3.937062,5.88953483 4.00557508,5.85697179 C4.34048317,5.68140952 4.95495153,5.31464081 5.18735866,4.8796172 C5.261514,4.74090562 5.26057363,4.55305979 5.20885297,4.4070476 C5.11172559,4.13310092 4.57517408,3.53792744 4.57517408,3.53792744 L5.39988357,3 L6.47070238,3.38224206 C6.23186151,2.5028722 5.97233174,1.62308364 7.87366696,0 L7.87366696,0.000113687544 C7.14572562,0.965320936 7.77600936,1.33867083 7.69392696,2.02329722 C8.36752565,0.933374736 9.79032527,0.789787368 10.8884333,0.334923505 C9.64315826,1.59850841 8.72300609,3.05795044 7.87524898,3.88361241 L8.6358507,4.15511863 C8.6358507,4.15511863 8.27501511,4.42489353 8.52743882,4.95911272 C8.56957789,5.04829846 8.6215686,5.12667085 8.67971976,5.19553247 C7.54569301,5.94640706 6.80000003,7.23368269 6.80000003,8.70000013 L6.80000003,8.80234816 C6.31732959,9.12491448 6,9.67479474 6,10.3000002 L6,14.3000003 C6,14.530995 6.04331804,14.7517071 6.12228848,14.9544711 Z" id="Combined-Shape" fill="#589A0F" fill-rule="nonzero"></path>
        <path d="M11.0000002,5.5 C9.22720009,5.5 7.80000003,6.92720006 7.80000003,8.70000013 L7.80000003,9.50000016 C7.35680001,9.50000016 7,9.85680017 7,10.3000002 L7,14.3000003 C7,14.7432004 7.35680001,15.1000004 7.80000003,15.1000004 L14.2000003,15.1000004 C14.6432003,15.1000004 15.0000003,14.7432004 15.0000003,14.3000003 L15.0000003,10.3000002 C15.0000003,9.85680017 14.6432003,9.50000016 14.2000003,9.50000016 L14.2000003,8.70000013 C14.2000003,6.92720006 12.7728002,5.5 11.0000002,5.5 Z M11.0000002,7.10000006 C11.8864002,7.10000006 12.6000002,7.81360009 12.6000002,8.70000013 L12.6000002,9.50000016 L9.4000001,9.50000016 L9.4000001,8.70000013 C9.4000001,7.81360009 10.1136001,7.10000006 11.0000002,7.10000006 Z" id="Shape" fill="#589A0F" fill-rule="nonzero"></path>
    </g>
</svg>
Loading