browser_secure_transport_insecure_scheme.js (6501B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* Any copyright is dedicated to the Public Domain. 4 * http://creativecommons.org/publicdomain/zero/1.0/ */ 5 6 // Test that an insecure resource routed over a secure transport is considered 7 // insecure in terms of the site identity panel. We achieve this by running an 8 // HTTP-over-TLS "proxy" and having Firefox request an http:// URI over it. 9 10 const NOT_SECURE_LABEL = Services.prefs.getBoolPref( 11 "security.insecure_connection_text.enabled" 12 ) 13 ? "notSecure notSecureText" 14 : "notSecure"; 15 16 /** 17 * Tests that the page info dialog "security" section labels a 18 * connection as unencrypted and does not show certificate. 19 * 20 * @param {string} uri - URI of the page to test with. 21 */ 22 async function testPageInfoNotEncrypted(uri) { 23 let pageInfo = BrowserCommands.pageInfo(uri, "securityTab"); 24 await BrowserTestUtils.waitForEvent(pageInfo, "load"); 25 let pageInfoDoc = pageInfo.document; 26 let securityTab = pageInfoDoc.getElementById("securityTab"); 27 await TestUtils.waitForCondition( 28 () => BrowserTestUtils.isVisible(securityTab), 29 "Security tab should be visible." 30 ); 31 32 let secLabel = pageInfoDoc.getElementById("security-technical-shortform"); 33 await TestUtils.waitForCondition( 34 () => secLabel.value == "Connection Not Encrypted", 35 "pageInfo 'Security Details' should show not encrypted" 36 ); 37 38 let viewCertBtn = pageInfoDoc.getElementById("security-view-cert"); 39 ok( 40 viewCertBtn.collapsed, 41 "pageInfo 'View Cert' button should not be visible" 42 ); 43 pageInfo.close(); 44 } 45 46 // But first, a quick test that we don't incorrectly treat a 47 // blob:https://example.com URI as secure. 48 add_task(async function () { 49 let uri = 50 getRootDirectory(gTestPath).replace( 51 "chrome://mochitests/content", 52 "https://example.com" 53 ) + "dummy_page.html"; 54 await BrowserTestUtils.withNewTab(uri, async browser => { 55 await SpecialPowers.spawn(browser, [], async () => { 56 let debug = { hello: "world" }; 57 let blob = new Blob([JSON.stringify(debug, null, 2)], { 58 type: "application/json", 59 }); 60 let blobUri = URL.createObjectURL(blob); 61 content.document.location = blobUri; 62 }); 63 await BrowserTestUtils.browserLoaded(browser); 64 let identityMode = window.document.getElementById("identity-box").className; 65 is(identityMode, "localResource", "identity should be 'localResource'"); 66 await testPageInfoNotEncrypted(uri); 67 }); 68 }); 69 70 // This server pretends to be a HTTP over TLS proxy. It isn't really, but this 71 // is sufficient for the purposes of this test. 72 function startServer(cert) { 73 let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance( 74 Ci.nsITLSServerSocket 75 ); 76 tlsServer.init(-1, true, -1); 77 tlsServer.serverCert = cert; 78 79 let input, output; 80 81 let listener = { 82 onSocketAccepted(socket, transport) { 83 let connectionInfo = transport.securityCallbacks.getInterface( 84 Ci.nsITLSServerConnectionInfo 85 ); 86 connectionInfo.setSecurityObserver(listener); 87 input = transport.openInputStream(0, 0, 0); 88 output = transport.openOutputStream(0, 0, 0); 89 }, 90 91 onHandshakeDone() { 92 input.asyncWait( 93 { 94 onInputStreamReady(readyInput) { 95 try { 96 let request = NetUtil.readInputStreamToString( 97 readyInput, 98 readyInput.available() 99 ); 100 ok( 101 request.startsWith("GET ") && request.includes("HTTP/1.1"), 102 "expecting an HTTP/1.1 GET request" 103 ); 104 let response = 105 "HTTP/1.1 200 OK\r\nContent-Type:text/plain\r\n" + 106 "Connection:Close\r\nContent-Length:2\r\n\r\nOK"; 107 output.write(response, response.length); 108 } catch (e) { 109 info(e); 110 } 111 }, 112 }, 113 0, 114 0, 115 Services.tm.currentThread 116 ); 117 }, 118 119 onStopListening() { 120 input.close(); 121 output.close(); 122 }, 123 }; 124 125 tlsServer.setSessionTickets(false); 126 tlsServer.asyncListen(listener); 127 128 return tlsServer; 129 } 130 131 add_task(async function () { 132 await SpecialPowers.pushPrefEnv({ 133 // This test fails on some platforms if we leave IPv6 enabled. 134 set: [["network.dns.disableIPv6", true]], 135 }); 136 137 let certOverrideService = Cc[ 138 "@mozilla.org/security/certoverride;1" 139 ].getService(Ci.nsICertOverrideService); 140 141 let cert = getTestServerCertificate(); 142 // Start the proxy and configure Firefox to trust its certificate. 143 let server = startServer(cert); 144 certOverrideService.rememberValidityOverride( 145 "localhost", 146 server.port, 147 {}, 148 cert, 149 true 150 ); 151 // Configure Firefox to use the proxy. 152 let systemProxySettings = { 153 QueryInterface: ChromeUtils.generateQI(["nsISystemProxySettings"]), 154 mainThreadOnly: true, 155 PACURI: null, 156 getProxyForURI: () => { 157 return `HTTPS localhost:${server.port}`; 158 }, 159 }; 160 let oldProxyType = Services.prefs.getIntPref("network.proxy.type"); 161 Services.prefs.setIntPref( 162 "network.proxy.type", 163 Ci.nsIProtocolProxyService.PROXYCONFIG_SYSTEM 164 ); 165 let { MockRegistrar } = ChromeUtils.importESModule( 166 "resource://testing-common/MockRegistrar.sys.mjs" 167 ); 168 let mockProxy = MockRegistrar.register( 169 "@mozilla.org/system-proxy-settings;1", 170 systemProxySettings 171 ); 172 // Register cleanup to undo the configuration changes we've made. 173 registerCleanupFunction(() => { 174 certOverrideService.clearValidityOverride("localhost", server.port, {}); 175 Services.prefs.setIntPref("network.proxy.type", oldProxyType); 176 MockRegistrar.unregister(mockProxy); 177 server.close(); 178 }); 179 180 // Navigate to 'http://example.com'. Our proxy settings will route this via 181 // the "proxy" we just started. Even though our connection to the proxy is 182 // secure, in a real situation the connection from the proxy to 183 // http://example.com won't be secure, so we treat it as not secure. 184 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 185 await BrowserTestUtils.withNewTab("http://example.com/", async () => { 186 let identityMode = window.document.getElementById("identity-box").className; 187 is( 188 identityMode, 189 NOT_SECURE_LABEL, 190 `identity should be '${NOT_SECURE_LABEL}'` 191 ); 192 193 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 194 await testPageInfoNotEncrypted("http://example.com"); 195 }); 196 });