Ticket #23247: 0001-PATCH-Bug-23247-Communicating-security-expectations-(tor-browser).patch

File 0001-PATCH-Bug-23247-Communicating-security-expectations-(tor-browser).patch, 36.3 KB (added by pospeselr, 16 months ago)
  • browser/base/content/browser.js

    From 67e99596b13ffcde6ccb3ed154e31907701abe0f Mon Sep 17 00:00:00 2001
    From: Richard Pospesel <richard@torproject.org>
    Date: Fri, 8 Jun 2018 13:38:40 -0700
    Subject: [PATCH] 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.
    ---
     browser/base/content/browser.js               | 66 ++++++++++++-------
     browser/base/content/pageinfo/security.js     | 56 +++++++++++++---
     .../identity-block/identity-block.inc.css     | 20 ++++++
     .../shared/identity-block/onion-disabled.svg  |  9 +++
     .../shared/identity-block/onion-lock.svg      |  9 +++
     .../themes/shared/identity-block/onion.svg    |  8 +++
     browser/themes/shared/jar.inc.mn              |  3 +
     dom/base/nsContentUtils.cpp                   | 21 ++++++
     dom/base/nsContentUtils.h                     |  5 ++
     dom/base/nsGlobalWindowOuter.cpp              |  3 +-
     dom/presentation/PresentationRequest.cpp      |  3 +-
     dom/security/nsMixedContentBlocker.cpp        | 17 ++++-
     .../manager/ssl/nsSecureBrowserUIImpl.cpp     | 57 +++++++++-------
     13 files changed, 215 insertions(+), 62 deletions(-)
     create mode 100644 browser/themes/shared/identity-block/onion-disabled.svg
     create mode 100644 browser/themes/shared/identity-block/onion-lock.svg
     create mode 100644 browser/themes/shared/identity-block/onion.svg
    
    diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
    index 68bbe3af99e9..c471a2152d78 100644
    a b var gIdentityHandler = { 
    75027502
    75037503  get _hasInsecureLoginForms() {
    75047504    // checks if the page has been flagged for an insecure login. Also checks
    75057505    // if the pref to degrade the UI is set to true
    75067506    return LoginManagerParent.hasInsecureLoginForms(gBrowser.selectedBrowser) &&
    75077507           Services.prefs.getBoolPref("security.insecure_password.ui.enabled");
    75087508  },
    75097509
     7510  get _uriIsOnionHost() {
     7511    return this._uriHasHost ? this._uri.host.toLowerCase().endsWith(".onion") : false;
     7512  },
     7513
    75107514  // smart getters
    75117515  get _identityPopup() {
    75127516    delete this._identityPopup;
    75137517    return this._identityPopup = document.getElementById("identity-popup");
    75147518  },
    75157519  get _identityBox() {
    75167520    delete this._identityBox;
    75177521    return this._identityBox = document.getElementById("identity-box");
    var gIdentityHandler = { 
    78017805  /**
    78027806   * Return the CSS class name to set on the "fullscreen-warning" element to
    78037807   * display information about connection security in the notification shown
    78047808   * when a site enters the fullscreen mode.
    78057809   */
    78067810  get pointerlockFsWarningClassName() {
    78077811    // Note that the fullscreen warning does not handle _isSecureInternalUI.
    78087812    if (this._uriHasHost && this._isEV) {
    7809       return "verifiedIdentity";
     7813      return this._uriIsOnionHost ? "onionVerifiedIdentity" : "verifiedIdentity";
    78107814    }
    78117815    if (this._uriHasHost && this._isSecure) {
    7812       return "verifiedDomain";
     7816      return this._uriIsOnionHost ? "onionVerifiedDomain" : "verifiedDomain";
    78137817    }
    7814     return "unknownIdentity";
     7818    return this._uriIsOnionHost ? "onionUnknownIdentity" : "unknownIdentity";
    78157819  },
    78167820
    78177821  /**
    78187822   * Updates the identity block user interface with the data from this object.
    78197823   */
    78207824  refreshIdentityBlock() {
    78217825    if (!this._identityBox) {
    78227826      return;
    var gIdentityHandler = { 
    78277831    let icon_country_label = "";
    78287832    let icon_labels_dir = "ltr";
    78297833
    78307834    if (this._isSecureInternalUI) {
    78317835      this._identityBox.className = "chromeUI";
    78327836      let brandBundle = document.getElementById("bundle_brand");
    78337837      icon_label = brandBundle.getString("brandShorterName");
    78347838    } else if (this._uriHasHost && this._isEV) {
    7835       this._identityBox.className = "verifiedIdentity";
     7839      let uriIsOnionHost = this._uriIsOnionHost;
     7840      this._identityBox.className = uriIsOnionHost ? "onionVerifiedIdentity" : "verifiedIdentity";
    78367841      if (this._isMixedActiveContentBlocked) {
    7837         this._identityBox.classList.add("mixedActiveBlocked");
     7842        this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveBlocked" : "mixedActiveBlocked");
    78387843      }
    78397844
    78407845      if (!this._isCertUserOverridden) {
    78417846        // If it's identified, then we can populate the dialog with credentials
    78427847        let iData = this.getIdentityData();
    78437848        tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
    78447849                                                      [iData.caOrg]);
    78457850        icon_label = iData.subjectOrg;
    var gIdentityHandler = { 
    78557860        icon_labels_dir = /^[\u0590-\u08ff\ufb1d-\ufdff\ufe70-\ufefc\ud802\ud803\ud83a\ud83b]/.test(icon_label) ?
    78567861                          "rtl" : "ltr";
    78577862      }
    78587863    } else if (this._pageExtensionPolicy) {
    78597864      this._identityBox.className = "extensionPage";
    78607865      let extensionName = this._pageExtensionPolicy.name;
    78617866      icon_label = gNavigatorBundle.getFormattedString(
    78627867        "identity.extension.label", [extensionName]);
    7863     } else if (this._uriHasHost && this._isSecure) {
    7864       this._identityBox.className = "verifiedDomain";
     7868    // _isSecure implicitly includes onion services, which may not have an SSL certificate
     7869    } else if (this._uriHasHost && this._isSecure && this._sslStatus != null) {
     7870      let uriIsOnionHost = this._uriIsOnionHost;
     7871      if (uriIsOnionHost) {
     7872        this._identityBox.className = this._sslStatus.serverCert.isSelfSigned ? "onionSelfSigned" : "onionVerifiedDomain";
     7873      } else {
     7874        this._identityBox.className = "verifiedDomain";
     7875      }
     7876
    78657877      if (this._isMixedActiveContentBlocked) {
    7866         this._identityBox.classList.add("mixedActiveBlocked");
     7878        this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveBlocked" : "mixedActiveBlocked");
    78677879      }
    78687880      if (!this._isCertUserOverridden) {
    78697881        // It's a normal cert, verifier is the CA Org.
    78707882        tooltip = gNavigatorBundle.getFormattedString("identity.identified.verifier",
    78717883                                                      [this.getIdentityData().caOrg]);
    78727884      }
    78737885    } else if (!this._uriHasHost) {
    78747886      this._identityBox.className = "unknownIdentity";
    78757887    } else if (gBrowser.selectedBrowser.documentURI &&
    78767888               (gBrowser.selectedBrowser.documentURI.scheme == "about" ||
    78777889               gBrowser.selectedBrowser.documentURI.scheme == "chrome")) {
    78787890        // For net errors we should not show notSecure as it's likely confusing
    78797891      this._identityBox.className = "unknownIdentity";
    78807892    } else {
     7893      let uriIsOnionHost = this._uriIsOnionHost;
    78817894      if (this._isBroken) {
    7882         this._identityBox.className = "unknownIdentity";
     7895        this._identityBox.className = uriIsOnionHost ? "onionUnknownIdentity" : "unknownIdentity";
    78837896
    78847897        if (this._isMixedActiveContentLoaded) {
    7885           this._identityBox.classList.add("mixedActiveContent");
     7898          this._identityBox.classList.add(uriIsOnionHost ? "onionMixedActiveContent" : "mixedActiveContent");
    78867899        } else if (this._isMixedActiveContentBlocked) {
    7887           this._identityBox.classList.add("mixedDisplayContentLoadedActiveBlocked");
     7900          this._identityBox.classList.add(uriIsOnionHost ? "onionMixedDisplayContentLoadedActiveBlocked" : "mixedDisplayContentLoadedActiveBlocked");
    78887901        } else if (this._isMixedPassiveContentLoaded) {
    7889           this._identityBox.classList.add("mixedDisplayContent");
     7902          this._identityBox.classList.add(uriIsOnionHost ? "onionMixedDisplayContent" : "mixedDisplayContent");
    78907903        } else {
    78917904          this._identityBox.classList.add("weakCipher");
    78927905        }
    78937906      } else {
    7894         let warnOnInsecure = Services.prefs.getBoolPref("security.insecure_connection_icon.enabled") ||
    7895                              (Services.prefs.getBoolPref("security.insecure_connection_icon.pbmode.enabled") &&
    7896                              PrivateBrowsingUtils.isWindowPrivate(window));
    7897         let className = warnOnInsecure ? "notSecure" : "unknownIdentity";
    7898         this._identityBox.className = className;
    7899 
    7900         let warnTextOnInsecure = Services.prefs.getBoolPref("security.insecure_connection_text.enabled") ||
    7901                                  (Services.prefs.getBoolPref("security.insecure_connection_text.pbmode.enabled") &&
    7902                                  PrivateBrowsingUtils.isWindowPrivate(window));
    7903         if (warnTextOnInsecure) {
    7904           icon_label = gNavigatorBundle.getString("identity.notSecure.label");
    7905           this._identityBox.classList.add("notSecureText");
     7907        if (!uriIsOnionHost) {
     7908          let warnOnInsecure = Services.prefs.getBoolPref("security.insecure_connection_icon.enabled") ||
     7909                               (Services.prefs.getBoolPref("security.insecure_connection_icon.pbmode.enabled") &&
     7910                               PrivateBrowsingUtils.isWindowPrivate(window));
     7911          let className = warnOnInsecure ? "notSecure" : "unknownIdentity";
     7912          this._identityBox.className = className;
     7913
     7914          let warnTextOnInsecure = Services.prefs.getBoolPref("security.insecure_connection_text.enabled") ||
     7915                                   (Services.prefs.getBoolPref("security.insecure_connection_text.pbmode.enabled") &&
     7916                                   PrivateBrowsingUtils.isWindowPrivate(window));
     7917          if (warnTextOnInsecure) {
     7918            icon_label = gNavigatorBundle.getString("identity.notSecure.label");
     7919            this._identityBox.classList.add("notSecureText");
     7920          }
     7921        // http onion is secure
     7922        } else {
     7923          this._identityBox.className = "onionUnknownIdentity";
    79067924        }
    79077925      }
    79087926      if (this._hasInsecureLoginForms) {
    79097927        // Insecure login forms can only be present on "unknown identity"
    79107928        // pages, either already insecure or with mixed active content loaded.
    79117929        this._identityBox.classList.add("insecureLoginForms");
    79127930      }
    79137931    }
  • browser/base/content/pageinfo/security.js

    diff --git a/browser/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js
    index 2d6c5fb1d396..493f9401e900 100644
    a b ChromeUtils.import("resource://gre/modules/BrowserUtils.jsm"); 
    77
    88/* import-globals-from pageInfo.js */
    99
    1010ChromeUtils.defineModuleGetter(this, "LoginHelper",
    1111                               "resource://gre/modules/LoginHelper.jsm");
    1212ChromeUtils.defineModuleGetter(this, "PluralForm",
    1313                               "resource://gre/modules/PluralForm.jsm");
    1414
     15XPCOMUtils.defineLazyGetter(this, "gTorButtonBundle", function() {
     16  return Services.strings.createBundle("chrome://torbutton/locale/torbutton.properties");
     17});
     18
    1519var security = {
    1620  init(uri, windowInfo) {
    1721    this.uri = uri;
    1822    this.windowInfo = windowInfo;
    1923  },
    2024
    2125  // Display the server certificate (static)
    2226  viewCert() {
    var security = { 
    4347      (ui.state & Ci.nsIWebProgressListener.STATE_IS_BROKEN);
    4448    var isMixed =
    4549      (ui.state & (Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT |
    4650                   Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT));
    4751    var isInsecure =
    4852      (ui.state & Ci.nsIWebProgressListener.STATE_IS_INSECURE);
    4953    var isEV =
    5054      (ui.state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL);
     55    var isOnion = hostName.endsWith(".onion");
     56
    5157    ui.QueryInterface(nsISSLStatusProvider);
    5258    var status = ui.SSLStatus;
    5359
    5460    if (!isInsecure && status) {
    5561      status.QueryInterface(nsISSLStatus);
    5662      var cert = status.serverCert;
    5763      var issuerName = cert.issuerOrganization || cert.issuerName;
    5864
    var security = { 
    6066        hostName,
    6167        cAName: issuerName,
    6268        encryptionAlgorithm: undefined,
    6369        encryptionStrength: undefined,
    6470        version: undefined,
    6571        isBroken,
    6672        isMixed,
    6773        isEV,
     74        isOnion,
    6875        cert,
    6976        certificateTransparency: undefined
    7077      };
    7178
    7279      var version;
    7380      try {
    7481        retval.encryptionAlgorithm = status.cipherName;
    7582        retval.encryptionStrength = status.secretKeyLength;
    var security = { 
    116123      hostName,
    117124      cAName: "",
    118125      encryptionAlgorithm: "",
    119126      encryptionStrength: 0,
    120127      version: "",
    121128      isBroken,
    122129      isMixed,
    123130      isEV,
     131      isOnion,
    124132      cert: null,
    125133      certificateTransparency: null
    126134    };
    127135  },
    128136
    129137  // Find the secureBrowserUI object (if present)
    130138  _getSecurityUI() {
    131139    if (window.opener.gBrowser)
    function securityOnLoad(uri, windowInfo) { 
    252260      hdr = pkiBundle.getFormattedString("pageInfo_BrokenEncryption",
    253261                                         [info.encryptionAlgorithm,
    254262                                          info.encryptionStrength + "",
    255263                                          info.version]);
    256264      msg1 = pkiBundle.getString("pageInfo_WeakCipher");
    257265    }
    258266    msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
    259267  } else if (info.encryptionStrength > 0) {
    260     hdr = pkiBundle.getFormattedString("pageInfo_EncryptionWithBitsAndProtocol",
    261                                        [info.encryptionAlgorithm,
    262                                         info.encryptionStrength + "",
    263                                         info.version]);
     268    if (!info.isOnion) {
     269      hdr = pkiBundle.getFormattedString("pageInfo_EncryptionWithBitsAndProtocol",
     270                                         [info.encryptionAlgorithm,
     271                                          info.encryptionStrength + "",
     272                                          info.version]);
     273    } else {
     274      try {
     275        hdr = gTorButtonBundle.formatStringFromName("pageInfo_OnionEncryptionWithBitsAndProtocol",
     276                                         [info.encryptionAlgorithm,
     277                                          info.encryptionStrength + "",
     278                                          info.version], 3);
     279      } catch(err) {
     280        hdr = "Connection Encrypted (Onion Service, "
     281               + info.encryptionAlgorithm
     282               + ", "
     283               + info.encryptionStrength
     284               + " bit keys, "
     285               + info.version
     286               + ")";
     287      }
     288    }
    264289    msg1 = pkiBundle.getString("pageInfo_Privacy_Encrypted1");
    265290    msg2 = pkiBundle.getString("pageInfo_Privacy_Encrypted2");
    266291    security._cert = info.cert;
    267292  } else {
    268     hdr = pkiBundle.getString("pageInfo_NoEncryption");
    269     if (info.hostName != null)
    270       msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]);
    271     else
    272       msg1 = pkiBundle.getString("pageInfo_Privacy_None4");
    273     msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
     293    if (!info.isOnion) {
     294      hdr = pkiBundle.getString("pageInfo_NoEncryption");
     295      if (info.hostName != null) {
     296        msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [info.hostName]);
     297      } else {
     298        msg1 = pkiBundle.getString("pageInfo_Privacy_None4");
     299      }
     300      msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
     301    } else {
     302      try {
     303        hdr = gTorButtonBundle.GetStringFromName("pageInfo_OnionEncryption");
     304      } catch (err) {
     305        hdr = "Connection Encrypted (Onion Service)";
     306      }
     307
     308      msg1 = pkiBundle.getString("pageInfo_Privacy_Encrypted1");
     309      msg2 = pkiBundle.getString("pageInfo_Privacy_Encrypted2");
     310    }
    274311  }
    275312  setText("security-technical-shortform", hdr);
    276313  setText("security-technical-longform1", msg1);
    277314  setText("security-technical-longform2", msg2);
    278315
    279316  const ctStatus =
    280317    document.getElementById("security-technical-certificate-transparency");
    281318  if (info.certificateTransparency) {
  • browser/themes/shared/identity-block/identity-block.inc.css

    diff --git a/browser/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css
    index ac85070708c4..36bab9f13715 100644
    a b  
    195195
    196196#urlbar[pageproxystate="valid"] > #identity-box.notSecure > #connection-icon,
    197197#urlbar[pageproxystate="valid"] > #identity-box.insecureLoginForms > #connection-icon,
    198198#urlbar[pageproxystate="valid"] > #identity-box.mixedActiveContent > #connection-icon {
    199199  list-style-image: url(chrome://browser/skin/connection-mixed-active-loaded.svg);
    200200  visibility: visible;
    201201}
    202202
     203#urlbar[pageproxystate="valid"] > #identity-box.onionUnknownIdentity > #connection-icon,
     204#urlbar[pageproxystate="valid"] > #identity-box.onionSelfSigned > #connection-icon {
     205  list-style-image: url(chrome://browser/skin/onion.svg);
     206  visibility: visible;
     207}
     208
     209#urlbar[pageproxystate="valid"] > #identity-box.onionVerifiedDomain > #connection-icon,
     210#urlbar[pageproxystate="valid"] > #identity-box.onionVerifiedIdentity > #connection-icon,
     211#urlbar[pageproxystate="valid"] > #identity-box.onionMixedActiveBlocked > #connection-icon {
     212  list-style-image: url(chrome://browser/skin/onion-lock.svg);
     213  visibility: visible;
     214}
     215
     216#urlbar[pageproxystate="valid"] > #identity-box.onionMixedActiveContent > #connection-icon,
     217#urlbar[pageproxystate="valid"] > #identity-box.onionMixedDisplayContentLoadedActiveBlocked > #connection-icon,
     218#urlbar[pageproxystate="valid"] > #identity-box.onionMixedDisplayContent > #connection-icon {
     219  list-style-image: url(chrome://browser/skin/onion-disabled.svg);
     220  visibility: visible;
     221}
     222
    203223#identity-box.extensionPage > #extension-icon {
    204224  list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.svg);
    205225  visibility: visible;
    206226}
    207227
    208228/* REMOTE CONTROL ICON */
    209229
    210230#main-window[remotecontrol] #remote-control-icon {
  • new file rowser/themes/shared/identity-block/onion-disabled.svg

    diff --git a/browser/themes/shared/identity-block/onion-disabled.svg b/browser/themes/shared/identity-block/onion-disabled.svg
    new file mode 100644
    index 000000000000..f5b20a87a923
    - +  
     1<?xml version="1.0" encoding="UTF-8"?>
     2<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">
     3    <title>onion-disabled</title>
     4    <defs></defs>
     5    <g id="onion-disabled" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
     6        <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>
     7        <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>
     8    </g>
     9</svg>
  • new file rowser/themes/shared/identity-block/onion-lock.svg

    diff --git a/browser/themes/shared/identity-block/onion-lock.svg b/browser/themes/shared/identity-block/onion-lock.svg
    new file mode 100644
    index 000000000000..c88247eb19d7
    - +  
     1<?xml version="1.0" encoding="UTF-8"?>
     2<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">
     3    <title>onion+lock</title>
     4    <defs></defs>
     5    <g id="onion+lock" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
     6        <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>
     7        <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>
     8    </g>
     9</svg>
  • new file rowser/themes/shared/identity-block/onion.svg

    diff --git a/browser/themes/shared/identity-block/onion.svg b/browser/themes/shared/identity-block/onion.svg
    new file mode 100644
    index 000000000000..e102f41c5991
    - +  
     1<?xml version="1.0" encoding="UTF-8"?>
     2<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">
     3    <title>onion</title>
     4    <defs></defs>
     5    <g id="onion" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
     6        <path d="M7.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 C12.6087813,6.47613299 14,8.18134675 14,10.2383803 C14,13.0968586 11.3137496,15 8,15 C4.68625036,15 2,13.0968586 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 Z" id="Combined-Shape" fill="#589A0F" fill-rule="nonzero"></path>
     7    </g>
     8</svg>
  • browser/themes/shared/jar.inc.mn

    diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn
    index 17debd82ddcd..3f59d7bfac19 100644
    a b  
    4040  skin/classic/browser/downloads/download-icons.svg            (../shared/downloads/download-icons.svg)
    4141  skin/classic/browser/downloads/notification-start-animation.svg  (../shared/downloads/notification-start-animation.svg)
    4242  skin/classic/browser/drm-icon.svg                            (../shared/drm-icon.svg)
    4343  skin/classic/browser/fullscreen/insecure.svg                 (../shared/fullscreen/insecure.svg)
    4444  skin/classic/browser/fullscreen/secure.svg                   (../shared/fullscreen/secure.svg)
    4545  skin/classic/browser/connection-secure.svg                   (../shared/identity-block/connection-secure.svg)
    4646  skin/classic/browser/connection-mixed-passive-loaded.svg     (../shared/identity-block/connection-mixed-passive-loaded.svg)
    4747  skin/classic/browser/connection-mixed-active-loaded.svg      (../shared/identity-block/connection-mixed-active-loaded.svg)
     48  skin/classic/browser/onion.svg                               (../shared/identity-block/onion.svg)
     49  skin/classic/browser/onion-lock.svg                          (../shared/identity-block/onion-lock.svg)
     50  skin/classic/browser/onion-disabled.svg                      (../shared/identity-block/onion-disabled.svg)
    4851  skin/classic/browser/identity-icon.svg                       (../shared/identity-block/identity-icon.svg)
    4952  skin/classic/browser/identity-icon-notice.svg                (../shared/identity-block/identity-icon-notice.svg)
    5053  skin/classic/browser/info.svg                                (../shared/info.svg)
    5154  skin/classic/browser/searchReset.css                         (../shared/searchReset.css)
    5255
    5356  skin/classic/browser/illustrations/error-session-restore.svg (../shared/illustrations/error-session-restore.svg)
    5457
    5558  skin/classic/browser/notification-icons/camera-blocked.svg                (../shared/notification-icons/camera-blocked.svg)
  • dom/base/nsContentUtils.cpp

    diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
    index 63e1ac06bf2d..8257283e65a2 100644
    a b nsContentUtils::HttpsStateIsModern(nsIDocument* aDocument) 
    1003410034    if (isTrustworthyOrigin) {
    1003510035      return true;
    1003610036    }
    1003710037  }
    1003810038
    1003910039  return false;
    1004010040}
    1004110041
     10042/* static */ bool
     10043nsContentUtils::DocumentHasOnionURI(nsIDocument* aDocument)
     10044{
     10045  if (!aDocument) {
     10046    return false;
     10047  }
     10048
     10049  nsIURI* uri = aDocument->GetDocumentURI();
     10050  if (!uri) {
     10051    return false;
     10052  }
     10053
     10054  nsAutoCString host;
     10055  if (NS_SUCCEEDED(uri->GetHost(host))) {
     10056    bool hasOnionURI = StringEndsWith(host, NS_LITERAL_CSTRING(".onion"));
     10057    return hasOnionURI;
     10058  }
     10059
     10060  return false;
     10061}
     10062
    1004210063/* static */ void
    1004310064nsContentUtils::TryToUpgradeElement(Element* aElement)
    1004410065{
    1004510066  NodeInfo* nodeInfo = aElement->NodeInfo();
    1004610067  RefPtr<nsAtom> typeAtom =
    1004710068    aElement->GetCustomElementData()->GetCustomElementType();
    1004810069
    1004910070  MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName()));
  • dom/base/nsContentUtils.h

    diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
    index 9ef79a569ea3..246dabf340de 100644
    a b public: 
    30443044  /**
    30453045   * Returns true if the "HTTPS state" of the document should be "modern". See:
    30463046   *
    30473047   * https://html.spec.whatwg.org/#concept-document-https-state
    30483048   * https://fetch.spec.whatwg.org/#concept-response-https-state
    30493049   */
    30503050  static bool HttpsStateIsModern(nsIDocument* aDocument);
    30513051
     3052  /**
     3053   * Returns true of the document's URI is a .onion
     3054   */
     3055  static bool DocumentHasOnionURI(nsIDocument* aDocument);
     3056
    30523057  /**
    30533058   * Try to upgrade an element.
    30543059   * https://html.spec.whatwg.org/multipage/custom-elements.html#concept-try-upgrade
    30553060   */
    30563061  static void TryToUpgradeElement(Element* aElement);
    30573062
    30583063  /**
    30593064   * Creates a new XUL or XHTML element applying any appropriate custom element
  • dom/base/nsGlobalWindowOuter.cpp

    diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
    index 7d947b653f70..e4b847406085 100644
    a b nsGlobalWindowOuter::ComputeIsSecureContext(nsIDocument* aDocument, SecureContex 
    14901490               "Creator window mismatch while setting Secure Context state");
    14911491    hadNonSecureContextCreator = !parentWin->IsSecureContext();
    14921492  }
    14931493
    14941494  if (hadNonSecureContextCreator) {
    14951495    return false;
    14961496  }
    14971497
    1498   if (nsContentUtils::HttpsStateIsModern(aDocument)) {
     1498  if (nsContentUtils::HttpsStateIsModern(aDocument) ||
     1499      nsContentUtils::DocumentHasOnionURI(aDocument)) {
    14991500    return true;
    15001501  }
    15011502
    15021503  if (principal->GetIsNullPrincipal()) {
    15031504    nsCOMPtr<nsIURI> uri = aDocument->GetOriginalURI();
    15041505    // IsOriginPotentiallyTrustworthy doesn't care about origin attributes so
    15051506    // it doesn't actually matter what we use here, but reusing the document
    15061507    // principal's attributes is convenient.
  • dom/presentation/PresentationRequest.cpp

    diff --git a/dom/presentation/PresentationRequest.cpp b/dom/presentation/PresentationRequest.cpp
    index 4c00150a359d..577aa3dd739e 100644
    a b PresentationRequest::IsProhibitMixedSecurityContexts(nsIDocument* aDocument) 
    507507  MOZ_ASSERT(aDocument);
    508508
    509509  if (nsContentUtils::IsChromeDoc(aDocument)) {
    510510    return true;
    511511  }
    512512
    513513  nsCOMPtr<nsIDocument> doc = aDocument;
    514514  while (doc && !nsContentUtils::IsChromeDoc(doc)) {
    515     if (nsContentUtils::HttpsStateIsModern(doc)) {
     515    if (nsContentUtils::HttpsStateIsModern(doc) ||
     516        nsContentUtils::DocumentHasOnionURI(doc)) {
    516517      return true;
    517518    }
    518519
    519520    doc = doc->GetParentDocument();
    520521  }
    521522
    522523  return false;
    523524}
  • dom/security/nsMixedContentBlocker.cpp

    diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp
    index adc0bfd80e88..7b0e5088a4de 100644
    a b nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect, 
    689689
    690690  // 4) Giving up. We still don't have a requesting location, therefore we can't tell
    691691  //    if this is a mixed content load. Deny to be safe.
    692692  if (!requestingLocation) {
    693693    *aDecision = REJECT_REQUEST;
    694694    return NS_OK;
    695695  }
    696696
    697   // Check the parent scheme. If it is not an HTTPS page then mixed content
     697  // Check the parent scheme. If it is not an HTTPS or .onion page then mixed content
    698698  // restrictions do not apply.
    699699  bool parentIsHttps;
    700700  nsCOMPtr<nsIURI> innerRequestingLocation = NS_GetInnermostURI(requestingLocation);
    701701  if (!innerRequestingLocation) {
    702702    NS_ERROR("Can't get innerURI from requestingLocation");
    703703    *aDecision = REJECT_REQUEST;
    704704    return NS_OK;
    705705  }
    706706
    707707  nsresult rv = innerRequestingLocation->SchemeIs("https", &parentIsHttps);
    708708  if (NS_FAILED(rv)) {
    709709    NS_ERROR("requestingLocation->SchemeIs failed");
    710710    *aDecision = REJECT_REQUEST;
    711711    return NS_OK;
    712712  }
    713713  if (!parentIsHttps) {
    714     *aDecision = ACCEPT;
    715     return NS_OK;
     714    nsAutoCString parentHost;
     715    rv = innerRequestingLocation->GetHost(parentHost);
     716    if (NS_FAILED(rv)) {
     717      NS_ERROR("requestingLocation->GetHost failed");
     718      *aDecision = REJECT_REQUEST;
     719      return NS_OK;
     720    }
     721
     722    bool parentIsOnion = StringEndsWith(parentHost, NS_LITERAL_CSTRING(".onion"));
     723    if (!parentIsOnion) {
     724      *aDecision = ACCEPT;
     725      return NS_OK;
     726    }
    716727  }
    717728
    718729  nsCOMPtr<nsIDocShell> docShell = NS_CP_GetDocShellFromContext(aRequestingContext);
    719730  NS_ENSURE_TRUE(docShell, NS_OK);
    720731
    721732  // Disallow mixed content loads for workers, shared workers and service
    722733  // workers.
    723734  if (isWorkerType) {
  • security/manager/ssl/nsSecureBrowserUIImpl.cpp

    diff --git a/security/manager/ssl/nsSecureBrowserUIImpl.cpp b/security/manager/ssl/nsSecureBrowserUIImpl.cpp
    index a2f24df7c4af..336901f0226e 100644
    a b nsSecureBrowserUIImpl::SetDocShell(nsIDocShell* aDocShell) 
    289289
    290290static uint32_t GetSecurityStateFromSecurityInfoAndRequest(nsISupports* info,
    291291                                                           nsIRequest* request)
    292292{
    293293  nsresult res;
    294294  uint32_t securityState;
    295295
    296296  nsCOMPtr<nsITransportSecurityInfo> psmInfo(do_QueryInterface(info));
     297  MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - info is %p\n",
     298                                          (nsISupports *)info));
    297299  if (!psmInfo) {
    298300    MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - no nsITransportSecurityInfo for %p\n",
    299301                                         (nsISupports *)info));
    300     return nsIWebProgressListener::STATE_IS_INSECURE;
     302    securityState = nsIWebProgressListener::STATE_IS_INSECURE;
     303  } else {
     304    res = psmInfo->GetSecurityState(&securityState);
     305    if (NS_FAILED(res)) {
     306      MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - GetSecurityState failed: %" PRIu32 "\n",
     307                                               static_cast<uint32_t>(res)));
     308      securityState = nsIWebProgressListener::STATE_IS_BROKEN;
     309    }
    301310  }
    302   MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - info is %p\n",
    303                                        (nsISupports *)info));
    304311
    305   res = psmInfo->GetSecurityState(&securityState);
    306   if (NS_FAILED(res)) {
    307     MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - GetSecurityState failed: %" PRIu32 "\n",
    308                                              static_cast<uint32_t>(res)));
    309     securityState = nsIWebProgressListener::STATE_IS_BROKEN;
     312  nsCOMPtr<nsIURI> uri;
     313  nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
     314  if (channel) {
     315    channel->GetURI(getter_AddRefs(uri));
     316  } else {
     317    nsCOMPtr<imgIRequest> imgRequest(do_QueryInterface(request));
     318    if (imgRequest) {
     319      imgRequest->GetURI(getter_AddRefs(uri));
     320    }
    310321  }
    311322
    312   if (securityState != nsIWebProgressListener::STATE_IS_INSECURE) {
    313     // A secure connection does not yield a secure per-uri channel if the
    314     // scheme is plain http.
    315 
    316     nsCOMPtr<nsIURI> uri;
    317     nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
    318     if (channel) {
    319       channel->GetURI(getter_AddRefs(uri));
    320     } else {
    321       nsCOMPtr<imgIRequest> imgRequest(do_QueryInterface(request));
    322       if (imgRequest) {
    323         imgRequest->GetURI(getter_AddRefs(uri));
    324       }
    325     }
    326     if (uri) {
     323  if (uri) {
     324    // http and ftp are always insecure
     325    if (securityState != nsIWebProgressListener::STATE_IS_INSECURE) {
    327326      bool isHttp, isFtp;
    328327      if ((NS_SUCCEEDED(uri->SchemeIs("http", &isHttp)) && isHttp) ||
    329328          (NS_SUCCEEDED(uri->SchemeIs("ftp", &isFtp)) && isFtp)) {
    330329        MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - "
    331330                                             "channel scheme is insecure.\n"));
    332331        securityState = nsIWebProgressListener::STATE_IS_INSECURE;
    333332      }
    334333    }
     334
     335    // any protocol routed over tor is secure
     336    if (securityState != nsIWebProgressListener::STATE_IS_SECURE) {
     337      nsAutoCString host;
     338      if (NS_SUCCEEDED(uri->GetHost(host))) {
     339        if (StringEndsWith(host, NS_LITERAL_CSTRING(".onion"))) {
     340          MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - "
     341                                                   "uri is onion.\n"));
     342          securityState = nsIWebProgressListener::STATE_IS_SECURE;
     343        }
     344      }
     345    }
    335346  }
    336347
    337348  MOZ_LOG(gSecureDocLog, LogLevel::Debug, ("SecureUI: GetSecurityState: - Returning %d\n",
    338349                                       securityState));
    339350  return securityState;
    340351}
    341352
    342353