[tor-commits] [tor-browser/tor-browser-88.0b4-10.5-1] Bug 23247: Communicating security expectations for .onion

sysrqb at torproject.org sysrqb at torproject.org
Tue Apr 20 02:43:32 UTC 2021


commit ae8803aa4e0b9cba6a56c88d0021befe19517c14
Author: Richard Pospesel <richard at torproject.org>
Date:   Fri Jun 8 13:38:40 2018 -0700

    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-siteIdentity.js       | 39 ++++++++-----
 browser/base/content/pageinfo/security.js          | 64 ++++++++++++++++++----
 .../shared/identity-block/identity-block.inc.css   | 19 +++++++
 .../themes/shared/identity-block/onion-slash.svg   |  5 ++
 .../themes/shared/identity-block/onion-warning.svg |  6 ++
 browser/themes/shared/identity-block/onion.svg     |  3 +
 browser/themes/shared/jar.inc.mn                   |  3 +
 dom/base/nsContentUtils.cpp                        | 19 +++++++
 dom/base/nsContentUtils.h                          |  5 ++
 dom/base/nsGlobalWindowOuter.cpp                   |  3 +-
 dom/ipc/WindowGlobalActor.cpp                      |  5 +-
 dom/ipc/WindowGlobalChild.cpp                      |  6 +-
 dom/security/nsMixedContentBlocker.cpp             | 16 +++++-
 .../modules/geckoview/GeckoViewProgress.jsm        |  4 ++
 security/manager/ssl/nsSecureBrowserUI.cpp         | 12 ++++
 15 files changed, 178 insertions(+), 31 deletions(-)

diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js
index c17d6c76394b..370e2af9477b 100644
--- a/browser/base/content/browser-siteIdentity.js
+++ b/browser/base/content/browser-siteIdentity.js
@@ -140,6 +140,10 @@ var gIdentityHandler = {
     );
   },
 
+  get _uriIsOnionHost() {
+    return this._uriHasHost ? this._uri.host.toLowerCase().endsWith(".onion") : false;
+  },
+
   get _isAboutNetErrorPage() {
     return (
       gBrowser.selectedBrowser.documentURI &&
@@ -735,9 +739,9 @@ var gIdentityHandler = {
   get pointerlockFsWarningClassName() {
     // Note that the fullscreen warning does not handle _isSecureInternalUI.
     if (this._uriHasHost && this._isSecureConnection) {
-      return "verifiedDomain";
+      return this._uriIsOnionHost ? "onionVerifiedDomain" : "verifiedDomain";
     }
-    return "unknownIdentity";
+    return this._uriIsOnionHost ? "onionUnknownIdentity" : "unknownIdentity";
   },
 
   /**
@@ -745,6 +749,10 @@ var gIdentityHandler = {
    * built-in (returns false) or imported (returns true).
    */
   _hasCustomRoot() {
+    if (!this._secInfo) {
+      return false;
+    }
+
     let issuerCert = null;
     issuerCert = this._secInfo.succeededCertChain[
       this._secInfo.succeededCertChain.length - 1
@@ -787,11 +795,13 @@ var gIdentityHandler = {
         "identity.extension.label",
         [extensionName]
       );
-    } else if (this._uriHasHost && this._isSecureConnection) {
+    } else if (this._uriHasHost && this._isSecureConnection && this._secInfo) {
       // This is a secure connection.
-      this._identityBox.className = "verifiedDomain";
+      // _isSecureConnection implicitly includes onion services, which may not have an SSL certificate
+      const uriIsOnionHost = this._uriIsOnionHost;
+      this._identityBox.className = uriIsOnionHost ? "onionVerifiedDomain" : "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.
@@ -802,17 +812,17 @@ var gIdentityHandler = {
       }
     } else if (this._isBrokenConnection) {
       // This is a secure connection, but something is wrong.
-      this._identityBox.className = "unknownIdentity";
+      const uriIsOnionHost = this._uriIsOnionHost;
+      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 {
+        // TODO: ignore weak https cipher for onionsites?
         this._identityBox.classList.add("weakCipher");
       }
     } else if (this._isAboutCertErrorPage) {
@@ -825,8 +835,8 @@ var gIdentityHandler = {
       // Network errors and blocked pages get a more neutral icon
       this._identityBox.className = "unknownIdentity";
     } else if (this._isPotentiallyTrustworthy) {
-      // This is a local resource (and shouldn't be marked insecure).
-      this._identityBox.className = "localResource";
+      // This is a local resource or an onion site (and shouldn't be marked insecure).
+      this._identityBox.className = this._uriIsOnionHost ? "onionUnknownIdentity" : "localResource";
     } else {
       // This is an insecure connection.
       let warnOnInsecure =
@@ -850,7 +860,8 @@ var gIdentityHandler = {
     }
 
     if (this._isCertUserOverridden) {
-      this._identityBox.classList.add("certUserOverridden");
+      const uriIsOnionHost = this._uriIsOnionHost;
+      this._identityBox.classList.add(uriIsOnionHost ? "onionCertUserOverridden" : "certUserOverridden");
       // Cert is trusted because of a security exception, verifier is a special string.
       tooltip = gNavigatorBundle.getString(
         "identity.identified.verified_by_you"
diff --git a/browser/base/content/pageinfo/security.js b/browser/base/content/pageinfo/security.js
index 6a2d09ec8442..192e9f763700 100644
--- a/browser/base/content/pageinfo/security.js
+++ b/browser/base/content/pageinfo/security.js
@@ -22,6 +22,13 @@ ChromeUtils.defineModuleGetter(
   "PluralForm",
   "resource://gre/modules/PluralForm.jsm"
 );
+XPCOMUtils.defineLazyGetter(
+  this,
+  "gTorButtonBundle",
+  function() {
+    return Services.strings.createBundle("chrome://torbutton/locale/torbutton.properties");
+  }
+);
 
 var security = {
   async init(uri, windowInfo) {
@@ -60,6 +67,11 @@ var security = {
       (Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT |
         Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT);
     var isEV = ui.state & Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
+    var isOnion = false;
+    const hostName = this.windowInfo.hostName;
+    if (hostName && hostName.endsWith(".onion")) {
+      isOnion = true;
+    }
 
     let retval = {
       cAName: "",
@@ -69,6 +81,7 @@ var security = {
       isBroken,
       isMixed,
       isEV,
+      isOnion,
       cert: null,
       certificateTransparency: null,
     };
@@ -107,6 +120,7 @@ var security = {
       isBroken,
       isMixed,
       isEV,
+      isOnion,
       cert,
       certChain: certChainArray,
       certificateTransparency: undefined,
@@ -349,22 +363,50 @@ async function securityOnLoad(uri, windowInfo) {
     }
     msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
   } else if (info.encryptionStrength > 0) {
-    hdr = pkiBundle.getFormattedString(
-      "pageInfo_EncryptionWithBitsAndProtocol",
-      [info.encryptionAlgorithm, info.encryptionStrength + "", info.version]
-    );
+    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]
+        );
+      } 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");
   } else {
-    hdr = pkiBundle.getString("pageInfo_NoEncryption");
-    if (windowInfo.hostName != null) {
-      msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [
-        windowInfo.hostName,
-      ]);
+    if (!info.isOnion) {
+      hdr = pkiBundle.getString("pageInfo_NoEncryption");
+      if (windowInfo.hostName != null) {
+        msg1 = pkiBundle.getFormattedString("pageInfo_Privacy_None1", [
+          windowInfo.hostName,
+        ]);
+      } else {
+        msg1 = pkiBundle.getString("pageInfo_Privacy_None4");
+      }
+      msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
     } else {
-      msg1 = pkiBundle.getString("pageInfo_Privacy_None4");
+      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");
     }
-    msg2 = pkiBundle.getString("pageInfo_Privacy_None2");
   }
   setText("security-technical-shortform", hdr);
   setText("security-technical-longform1", msg1);
diff --git a/browser/themes/shared/identity-block/identity-block.inc.css b/browser/themes/shared/identity-block/identity-block.inc.css
index 23b66d8a7747..8b5a9fa8ae82 100644
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -284,6 +284,25 @@ toolbar[brighttext] #identity-box[pageproxystate="valid"].chromeUI #identity-ico
   list-style-image: url(chrome://global/skin/icons/security-broken.svg);
 }
 
+#identity-box[pageproxystate="valid"].onionUnknownIdentity > #identity-icon,
+#identity-box[pageproxystate="valid"].onionVerifiedDomain > #identity-icon,
+#identity-box[pageproxystate="valid"].onionMixedActiveBlocked > #identity-icon {
+  list-style-image: url(chrome://browser/skin/onion.svg);
+  visibility: visible;
+}
+
+#identity-box[pageproxystate="valid"].onionMixedDisplayContent > #identity-icon,
+#identity-box[pageproxystate="valid"].onionMixedDisplayContentLoadedActiveBlocked > #identity-icon,
+#identity-box[pageproxystate="valid"].onionCertUserOverridden > #identity-icon {
+  list-style-image: url(chrome://browser/skin/onion-warning.svg);
+  visibility: visible;
+}
+
+#identity-box[pageproxystate="valid"].onionMixedActiveContent > #identity-icon {
+  list-style-image: url(chrome://browser/skin/onion-slash.svg);
+  visibility: visible;
+}
+
 #permissions-granted-icon {
   list-style-image: url(chrome://browser/skin/permissions.svg);
 }
diff --git a/browser/themes/shared/identity-block/onion-slash.svg b/browser/themes/shared/identity-block/onion-slash.svg
new file mode 100644
index 000000000000..e7c98b769482
--- /dev/null
+++ b/browser/themes/shared/identity-block/onion-slash.svg
@@ -0,0 +1,5 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path d="M3.409559 13.112147C3.409559 13.112147 8.200807 8.103115 8.200807 8.103115C8.200807 8.103115 8.200807 6.516403 8.200807 6.516403C8.620819 6.516403 9.009719 6.703075 9.274171 6.998639C9.274171 6.998639 10.160863 6.080835 10.160863 6.080835C9.663071 5.567487 8.978607 5.256367 8.200807 5.256367C8.200807 5.256367 8.200807 4.400787 8.200807 4.400787C9.196391 4.400787 10.098639 4.805243 10.736435 5.458595C10.736435 5.458595 11.623127 4.540791 11.623127 4.540791C10.751991 3.669655 9.538623 3.125195 8.200807 3.125195C8.200807 3.125195 8.200807 2.269615 8.200807 2.269615C9.756407 2.269615 11.172003 2.907411 12.214255 3.918551C12.214255 3.918551 13.100947 3.000747 13.100947 3.000747C11.825355 1.756267 10.098639 0.994023 8.185251 0.994023C4.311807 0.994023 1.185051 4.120779 1.185051 7.994223C1.185051 10.016503 2.040631 11.836555 3.409559 13.112147C3.409559 13.112147 3.409559 13.112147 3.409559 13.112147" fill-opacity="context-fill-opacity" fill="context-fill" />
+  <path d="M14.205423 4.416343C14.205423 4.416343 13.287619 5.380815 13.287619 5.380815C13.692075 6.158615 13.909859 7.045307 13.909859 7.994223C13.909859 11.152091 11.358675 13.718831 8.200807 13.718831C8.200807 13.718831 8.200807 12.863251 8.200807 12.863251C10.891995 12.863251 13.069835 10.669855 13.069835 7.978667C13.069835 7.278647 12.929831 6.625295 12.665379 6.018611C12.665379 6.018611 11.685351 7.045307 11.685351 7.045307C11.763131 7.340871 11.809799 7.651991 11.809799 7.963111C11.809799 9.954279 10.207531 11.556547 8.216363 11.572103C8.216363 11.572103 8.216363 10.716523 8.216363 10.716523C9.725295 10.700967 10.954219 9.472043 10.954219 7.963111C10.954219 7.916443 10.954219 7.854219 10.954219 7.807551C10.954219 7.807551 4.887379 14.169955 4.887379 14.169955C5.867407 14.698859 6.987439 14.994423 8.185251 14.994423C12.058695 14.994423 15.185451 11.867667 15.185451 7.994223C15.185451 6.687519 14.827663 5.474151 14.205423 4.416343C14.205423 4.416343 14.205423 4.416343 14.205423
  4.416343" fill-opacity="context-fill-opacity" fill="context-fill" />
+  <path d="M1.791735 15.461103C1.402835 15.461103 1.045047 15.212207 0.889487 14.838863C0.733927 14.465519 0.827267 14.014395 1.107271 13.734387C1.107271 13.734387 13.458735 0.822907 13.458735 0.822907C13.847635 0.434007 14.454319 0.449563 14.827663 0.838467C15.201007 1.227367 15.216563 1.865163 14.843223 2.269619C14.843223 2.269619 2.491759 15.181099 2.491759 15.181099C2.289531 15.352215 2.040635 15.461107 1.791739 15.461107C1.791739 15.461107 1.791735 15.461103 1.791735 15.461103" fill="#ff0039" />
+</svg>
diff --git a/browser/themes/shared/identity-block/onion-warning.svg b/browser/themes/shared/identity-block/onion-warning.svg
new file mode 100644
index 000000000000..d42a7dab7246
--- /dev/null
+++ b/browser/themes/shared/identity-block/onion-warning.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path d="M15.8630401732 14.127C15.8630401732 14.127 12.6649598146 7.716 12.6649598146 7.716C12.4469357756 7.279935 12.0003277145 7.0043454 11.5116853046 7.0043454C11.0230428947 7.0043454 10.5764348336 7.279935 10.3584107946 7.716C10.3584107946 7.716 7.1573218938 14.127 7.1573218938 14.127C6.95646770542 14.527294 6.97733695982 15.002669 7.21250176686 15.38393C7.4476665739 15.765191 7.86372750208 15.998191 8.3126020986 16.0C8.3126020986 16.0 14.7077599684 16.0 14.7077599684 16.0C15.1566344646 15.9982 15.572695794 15.765191 15.8078605007 15.38393C16.0430252075 15.002669 16.0638944619 14.527294 15.8630371647 14.127C15.8630371647 14.127 15.8630401732 14.127 15.8630401732 14.127" fill="#ffbf00" />
+  <path d="M11.5106824572 8.0C11.6210488221 7.99691 11.7223975832 8.060469 11.7674113916 8.161C11.7674113916 8.161 14.9644889028 14.573 14.9644889028 14.573C15.0126456349 14.66534 15.0076715118 14.776305 14.9514518866 14.864C14.9011992034 14.95041 14.8079143382 15.002854 14.7077599684 15.001048C14.7077599684 15.001048 8.3126020986 15.001048 8.3126020986 15.001048C8.2124480296 15.002854 8.1191607576 14.950409 8.0689101804 14.864C8.0124814615 14.77637 8.0075053327 14.665298 8.0558731642 14.573C8.0558731642 14.573 11.2529506754 8.161 11.2529506754 8.161C11.2981038796 8.0601247 11.3999560701 7.9964997 11.5106824572 8.0M11.5106824572 6.9999751C11.0194557096 6.9969427 10.5701148893 7.2754275 10.3554022524 7.716C10.3554022524 7.716 7.1573218938 14.127 7.1573218938 14.127C6.95646770542 14.527294 6.97733695982 15.002669 7.21250176686 15.38393C7.4476665739 15.765191 7.86372750208 15.998191 8.3126020986 16.0C8.3126020986 16.0 14.7077599684 16.0 14.7077599684 16.0C15.1566344646 15.9982 15.57269
 5794 15.765191 15.8078605007 15.38393C16.0430252075 15.002669 16.0638944619 14.527294 15.8630371647 14.127C15.8630371647 14.127 12.6649598146 7.716 12.6649598146 7.716C12.4504036219 7.2757546 12.0015481798 6.9973287 11.5106824572 6.9999751C11.5106824572 6.9999751 11.5106824572 6.9999751 11.5106824572 6.9999751" opacity="0.35" fill="#d76e00" />
+  <path d="M11.5327451 12.0C11.8096733867 12.0 12.0341688 11.776142 12.0341688 11.5C12.0341688 11.5 12.0341688 9.5 12.0341688 9.5C12.0341688 9.2238576 11.8096733867 9.0 11.5327451 9.0C11.2558168133 9.0 11.0313214 9.2238576 11.0313214 9.5C11.0313214 9.5 11.0313214 11.5 11.0313214 11.5C11.0313214 11.776142 11.2558168133 12.0 11.5327451 12.0C11.5327451 12.0 11.5327451 12.0 11.5327451 12.0M11.5327451 12.809C11.1500294496 12.809 10.8397775466 13.118371 10.8397775466 13.5C10.8397775466 13.881629 11.1500294496 14.191 11.5327451 14.191C11.9154607504 14.191 12.2257126534 13.881629 12.2257126534 13.5C12.2257126534 13.118371 11.9154607504 12.809 11.5327451 12.809C11.5327451 12.809 11.5327451 12.809 11.5327451 12.809" fill="#ffffff" />
+  <path d="M7.08030321348 6.552C7.90163523408 6.56 8.5645173655 7.225 8.5645173655 8.046C8.5645173655 8.866 7.90163523408 9.532 7.08030321348 9.54C7.08030321348 9.54 7.08030321348 6.552 7.08030321348 6.552M6.30610502068 13.756C6.30610502068 13.756 9.4991711423 7.353 9.4991711423 7.353C9.5453021227 7.259 9.6144985933 7.184 9.6716608951 7.098C9.2845617987 6.039 8.2756973143 5.277 7.08030321348 5.271C7.08030321348 5.271 7.08030321348 4.417 7.08030321348 4.417C8.5043465215 4.423 9.7238089599 5.251 10.3164917733 6.443C10.6795225321 6.21 11.1067355245 6.074 11.5519997701 6.074C11.5519997701 6.074 11.5620282441 6.074 11.5620282441 6.074C11.5620282441 6.074 11.5640339389 6.074 11.5640339389 6.074C11.5660396337 6.074 11.5690481759 6.075 11.5710538707 6.075C10.8108955415 4.35 9.0900094031 3.141 7.08030321348 3.135C7.08030321348 3.135 7.08030321348 2.281 7.08030321348 2.281C9.6716608951 2.288 11.8618796167 3.993 12.5889439817 6.34C13.0231769059 6.561 13.3922247491 6.9 13.6088397875 7.344C13.60
 88397875 7.344 14.1162805719 8.361 14.1162805719 8.361C14.1202919615 8.256 14.1313232829 8.152 14.1313232829 8.046C14.1313232829 4.155 10.9683425833 1.0 7.06626334988 1.0C3.16318126908 1.0 0.00020056948 4.155 0.00020056948 8.046C0.00020056948 11.603 2.64571201068 14.536 6.08046435568 15.015C6.03633907008 14.595 6.10252699848 14.16 6.30610502068 13.756C6.30610502068 13.756 6.30610502068 13.756 6.30610502068 13.756" fill-opacity="context-fill-opacity" fill="context-fill" />
+</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..b123a9786acc
--- /dev/null
+++ b/browser/themes/shared/identity-block/onion.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path d="M8.01435945 13.726867125C8.01435945 13.726867125 8.01435945 12.87830525 8.01435945 12.87830525C10.70227825 12.87051775 12.87869375 10.689666 12.87869375 7.9998060125C12.87869375 5.310140275 10.70227825 3.1292621 8.01435945 3.121500325C8.01435945 3.121500325 8.01435945 2.272938975 8.01435945 2.272938975C11.170899375 2.280892725 13.727061375 4.8415202875 13.727061375 7.9998060125C13.727061375 11.158285375 11.170899375 13.719105 8.01435945 13.726867125C8.01435945 13.726867125 8.01435945 13.726867125 8.01435945 13.726867125M8.01435945 10.756805625C9.5304373 10.74884925 10.75758175 9.5180185125 10.75758175 7.9998060125C10.75758175 6.4817875 9.5304373 5.2509564125 8.01435945 5.2430005625C8.01435945 5.2430005625 8.01435945 4.3946332875 8.01435945 4.3946332875C9.999251625 4.4023945375 11.60614275 6.013167425 11.60614275 7.9998060125C11.60614275 9.986639375 9.999251625 11.597411125 8.01435945 11.605172375C8.01435945 11.605172375 8.01435945 10.756805625 8.01435945 10.756805625M8.01
 435945 6.5157454625C8.8276046625 6.5235067125 9.484837025 7.184620575 9.484837025 7.9998060125C9.484837025 8.815185875 8.8276046625 9.4762985125 8.01435945 9.4840608125C8.01435945 9.4840608125 8.01435945 6.5157454625 8.01435945 6.5157454625M1.0 7.9998060125C1.0 11.8659705 4.1338360375 15.0 8.0000000875 15.0C11.8659705 15.0 15.0 11.8659705 15.0 7.9998060125C15.0 4.1338360375 11.8659705 1.0 8.0000000875 1.0C4.1338360375 1.0 1.0 4.1338360375 1.0 7.9998060125C1.0 7.9998060125 1.0 7.9998060125 1.0 7.9998060125" fill-rule="even-odd" fill-opacity="context-fill-opacity" fill="context-fill" />
+</svg>
diff --git a/browser/themes/shared/jar.inc.mn b/browser/themes/shared/jar.inc.mn
index 9a62864b3f1f..cbf18156a455 100644
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -52,6 +52,9 @@
   skin/classic/browser/downloads/notification-start-animation.svg  (../shared/downloads/notification-start-animation.svg)
   skin/classic/browser/drm-icon.svg                            (../shared/drm-icon.svg)
   skin/classic/browser/permissions.svg                         (../shared/identity-block/permissions.svg)
+  skin/classic/browser/onion.svg                               (../shared/identity-block/onion.svg)
+  skin/classic/browser/onion-slash.svg                         (../shared/identity-block/onion-slash.svg)
+  skin/classic/browser/onion-warning.svg                       (../shared/identity-block/onion-warning.svg)
   skin/classic/browser/newInstall.css                          (../shared/newInstall.css)
   skin/classic/browser/newInstallPage.css                      (../shared/newInstallPage.css)
   skin/classic/browser/illustrations/blue-berror.svg                        (../shared/illustrations/blue-berror.svg)
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index a5d51c1f6b63..5c328e3753d2 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -9204,6 +9204,25 @@ bool nsContentUtils::ComputeIsSecureContext(nsIChannel* aChannel) {
   return principal->GetIsOriginPotentiallyTrustworthy();
 }
 
+/* static */ bool nsContentUtils::DocumentHasOnionURI(Document* aDocument) {
+  if (!aDocument) {
+    return false;
+  }
+
+  nsIURI* uri = aDocument->GetDocumentURI();
+  if (!uri) {
+    return false;
+  }
+
+  nsAutoCString host;
+  if (NS_SUCCEEDED(uri->GetHost(host))) {
+    bool hasOnionURI = StringEndsWith(host, ".onion"_ns);
+    return hasOnionURI;
+  }
+
+  return false;
+}
+
 /* static */
 void nsContentUtils::TryToUpgradeElement(Element* aElement) {
   NodeInfo* nodeInfo = aElement->NodeInfo();
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 4fe89763c102..9fc33d9780a2 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2979,6 +2979,11 @@ class nsContentUtils {
    */
   static bool HttpsStateIsModern(Document* aDocument);
 
+  /**
+   * Returns true of the document's URI is a .onion
+   */
+  static bool DocumentHasOnionURI(Document* aDocument);
+
   /**
    * Returns true if the channel is for top-level window and is over secure
    * context.
diff --git a/dom/base/nsGlobalWindowOuter.cpp b/dom/base/nsGlobalWindowOuter.cpp
index 653c8c03fbdc..e5cb4d31d94c 100644
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -1881,7 +1881,8 @@ bool nsGlobalWindowOuter::ComputeIsSecureContext(Document* aDocument,
     return false;
   }
 
-  if (nsContentUtils::HttpsStateIsModern(aDocument)) {
+  if (nsContentUtils::HttpsStateIsModern(aDocument) ||
+      nsContentUtils::DocumentHasOnionURI(aDocument)) {
     return true;
   }
 
diff --git a/dom/ipc/WindowGlobalActor.cpp b/dom/ipc/WindowGlobalActor.cpp
index 64085dbe5d4c..b859ba966ac8 100644
--- a/dom/ipc/WindowGlobalActor.cpp
+++ b/dom/ipc/WindowGlobalActor.cpp
@@ -20,6 +20,7 @@
 #include "mozilla/net/CookieJarSettings.h"
 #include "mozilla/dom/WindowGlobalChild.h"
 #include "mozilla/dom/WindowGlobalParent.h"
+#include "mozilla/dom/nsMixedContentBlocker.h"
 
 #include "nsGlobalWindowInner.h"
 #include "nsNetUtil.h"
@@ -116,7 +117,9 @@ WindowGlobalInit WindowGlobalActor::WindowInitializer(
   // Init Mixed Content Fields
   nsCOMPtr<nsIURI> innerDocURI = NS_GetInnermostURI(doc->GetDocumentURI());
   if (innerDocURI) {
-    fields.mIsSecure = innerDocURI->SchemeIs("https");
+    fields.mIsSecure =
+        innerDocURI->SchemeIs("https") ||
+        nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(innerDocURI);
   }
   nsCOMPtr<nsIChannel> mixedChannel;
   aWindow->GetDocShell()->GetMixedContentChannel(getter_AddRefs(mixedChannel));
diff --git a/dom/ipc/WindowGlobalChild.cpp b/dom/ipc/WindowGlobalChild.cpp
index 92a6fd1e3b7c..6635b83bd339 100644
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -45,6 +45,8 @@
 #  include "GeckoProfiler.h"
 #endif
 
+#include "mozilla/dom/nsMixedContentBlocker.h"
+
 using namespace mozilla::ipc;
 using namespace mozilla::dom::ipc;
 
@@ -230,7 +232,9 @@ void WindowGlobalChild::OnNewDocument(Document* aDocument) {
   nsCOMPtr<nsIURI> innerDocURI =
       NS_GetInnermostURI(aDocument->GetDocumentURI());
   if (innerDocURI) {
-    txn.SetIsSecure(innerDocURI->SchemeIs("https"));
+    txn.SetIsSecure(
+        innerDocURI->SchemeIs("https") ||
+        nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(innerDocURI));
   }
   nsCOMPtr<nsIChannel> mixedChannel;
   mWindowGlobal->GetDocShell()->GetMixedContentChannel(
diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp
index 64a9f3178874..ba88625eda69 100644
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -638,8 +638,8 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
     return NS_OK;
   }
 
-  // Check the parent scheme. If it is not an HTTPS page then mixed content
-  // restrictions do not apply.
+  // Check the parent scheme. If it is not an HTTPS or .onion page then mixed
+  // content restrictions do not apply.
   nsCOMPtr<nsIURI> innerRequestingLocation =
       NS_GetInnermostURI(requestingLocation);
   if (!innerRequestingLocation) {
@@ -654,6 +654,17 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
 
   bool parentIsHttps = innerRequestingLocation->SchemeIs("https");
   if (!parentIsHttps) {
+    bool parentIsOnion = IsPotentiallyTrustworthyOnion(innerRequestingLocation);
+    if (!parentIsOnion) {
+      *aDecision = ACCEPT;
+      return NS_OK;
+    }
+  }
+
+  bool isHttpScheme = innerContentLocation->SchemeIs("http");
+  // .onion URLs are encrypted and authenticated. Don't treat them as mixed
+  // content if potentially trustworthy (i.e. whitelisted).
+  if (isHttpScheme && IsPotentiallyTrustworthyOnion(innerContentLocation)) {
     *aDecision = ACCEPT;
     MOZ_LOG(sMCBLog, LogLevel::Verbose,
             ("  -> decision: Request will be allowed because the requesting "
@@ -680,7 +691,6 @@ nsresult nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
     return NS_OK;
   }
 
-  bool isHttpScheme = innerContentLocation->SchemeIs("http");
   if (isHttpScheme && IsPotentiallyTrustworthyOrigin(innerContentLocation)) {
     *aDecision = ACCEPT;
     return NS_OK;
diff --git a/mobile/android/modules/geckoview/GeckoViewProgress.jsm b/mobile/android/modules/geckoview/GeckoViewProgress.jsm
index 17069dbe657f..c1346b1858cf 100644
--- a/mobile/android/modules/geckoview/GeckoViewProgress.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewProgress.jsm
@@ -145,6 +145,10 @@ var IdentityHandler = {
       result.host = uri.host;
     }
 
+    if (!aBrowser.securityUI.secInfo) {
+      return result;
+    }
+
     const cert = aBrowser.securityUI.secInfo.serverCert;
 
     result.certificate = aBrowser.securityUI.secInfo.serverCert.getBase64DERString();
diff --git a/security/manager/ssl/nsSecureBrowserUI.cpp b/security/manager/ssl/nsSecureBrowserUI.cpp
index b4de1a331ffc..f1ce39582854 100644
--- a/security/manager/ssl/nsSecureBrowserUI.cpp
+++ b/security/manager/ssl/nsSecureBrowserUI.cpp
@@ -9,6 +9,7 @@
 #include "mozilla/Logging.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/Document.h"
+#include "mozilla/dom/nsMixedContentBlocker.h"
 #include "nsContentUtils.h"
 #include "nsIChannel.h"
 #include "nsDocShell.h"
@@ -85,6 +86,17 @@ void nsSecureBrowserUI::RecomputeSecurityFlags() {
         }
       }
     }
+
+    // any protocol routed over tor is secure
+    if (!(mState & nsIWebProgressListener::STATE_IS_SECURE)) {
+      nsCOMPtr<nsIURI> innerDocURI = NS_GetInnermostURI(win->GetDocumentURI());
+      if (innerDocURI &&
+          nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(innerDocURI)) {
+        MOZ_LOG(gSecureBrowserUILog, LogLevel::Debug, ("  is onion"));
+        mState = (mState & ~nsIWebProgressListener::STATE_IS_INSECURE) |
+                 nsIWebProgressListener::STATE_IS_SECURE;
+      }
+    }
   }
 
   // Add upgraded-state flags when request has been





More information about the tor-commits mailing list