test_tls_flags.js (6885B)
1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*- 2 // Any copyright is dedicated to the Public Domain. 3 // http://creativecommons.org/publicdomain/zero/1.0/ 4 5 "use strict"; 6 7 // a fork of test_be_conservative 8 9 // Tests that nsIHttpChannelInternal.tlsFlags can be used to set the 10 // client max version level. Flags can also be used to set the 11 // level of intolerance rollback and to test out an experimental 1.3 12 // hello, though they are not tested here. 13 14 // Get a profile directory and ensure PSM initializes NSS. 15 do_get_profile(); 16 Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports); 17 18 class InputStreamCallback { 19 constructor(output) { 20 this.output = output; 21 this.stopped = false; 22 } 23 24 onInputStreamReady(stream) { 25 info("input stream ready"); 26 if (this.stopped) { 27 info("input stream callback stopped - bailing"); 28 return; 29 } 30 let available = 0; 31 try { 32 available = stream.available(); 33 } catch (e) { 34 // onInputStreamReady may fire when the stream has been closed. 35 equal( 36 e.result, 37 Cr.NS_BASE_STREAM_CLOSED, 38 "error should be NS_BASE_STREAM_CLOSED" 39 ); 40 } 41 if (available > 0) { 42 let request = NetUtil.readInputStreamToString(stream, available, { 43 charset: "utf8", 44 }); 45 ok( 46 request.startsWith("GET / HTTP/1.1\r\n"), 47 "Should get a simple GET / HTTP/1.1 request" 48 ); 49 let response = 50 "HTTP/1.1 200 OK\r\n" + 51 "Content-Length: 2\r\n" + 52 "Content-Type: text/plain\r\n" + 53 "\r\nOK"; 54 let written = this.output.write(response, response.length); 55 equal( 56 written, 57 response.length, 58 "should have been able to write entire response" 59 ); 60 } 61 this.output.close(); 62 info("done with input stream ready"); 63 } 64 65 stop() { 66 this.stopped = true; 67 this.output.close(); 68 } 69 } 70 71 class TLSServerSecurityObserver { 72 constructor(input, output, expectedVersion) { 73 this.input = input; 74 this.output = output; 75 this.expectedVersion = expectedVersion; 76 this.callbacks = []; 77 this.stopped = false; 78 } 79 80 onHandshakeDone(socket, status) { 81 info("TLS handshake done"); 82 info(`TLS version used: ${status.tlsVersionUsed}`); 83 info(this.expectedVersion); 84 equal( 85 status.tlsVersionUsed, 86 this.expectedVersion, 87 "expected version check" 88 ); 89 if (this.stopped) { 90 info("handshake done callback stopped - bailing"); 91 return; 92 } 93 94 let callback = new InputStreamCallback(this.output); 95 this.callbacks.push(callback); 96 this.input.asyncWait(callback, 0, 0, Services.tm.currentThread); 97 } 98 99 stop() { 100 this.stopped = true; 101 this.input.close(); 102 this.output.close(); 103 this.callbacks.forEach(callback => { 104 callback.stop(); 105 }); 106 } 107 } 108 109 function startServer( 110 cert, 111 minServerVersion, 112 maxServerVersion, 113 expectedVersion 114 ) { 115 let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance( 116 Ci.nsITLSServerSocket 117 ); 118 tlsServer.init(-1, true, -1); 119 tlsServer.serverCert = cert; 120 tlsServer.setVersionRange(minServerVersion, maxServerVersion); 121 tlsServer.setSessionTickets(false); 122 123 let listener = { 124 securityObservers: [], 125 126 onSocketAccepted(socket, transport) { 127 info("accepted TLS client connection"); 128 let connectionInfo = transport.securityCallbacks.getInterface( 129 Ci.nsITLSServerConnectionInfo 130 ); 131 let input = transport.openInputStream(0, 0, 0); 132 let output = transport.openOutputStream(0, 0, 0); 133 let securityObserver = new TLSServerSecurityObserver( 134 input, 135 output, 136 expectedVersion 137 ); 138 this.securityObservers.push(securityObserver); 139 connectionInfo.setSecurityObserver(securityObserver); 140 }, 141 142 // For some reason we get input stream callback events after we've stopped 143 // listening, so this ensures we just drop those events. 144 onStopListening() { 145 info("onStopListening"); 146 this.securityObservers.forEach(observer => { 147 observer.stop(); 148 }); 149 }, 150 }; 151 tlsServer.asyncListen(listener); 152 return tlsServer; 153 } 154 155 const hostname = "example.com"; 156 157 function storeCertOverride(port, cert) { 158 let certOverrideService = Cc[ 159 "@mozilla.org/security/certoverride;1" 160 ].getService(Ci.nsICertOverrideService); 161 certOverrideService.rememberValidityOverride(hostname, port, {}, cert, true); 162 } 163 164 function startClient(port, tlsFlags, expectSuccess) { 165 let req = new XMLHttpRequest(); 166 req.open("GET", `https://${hostname}:${port}`); 167 let internalChannel = req.channel.QueryInterface(Ci.nsIHttpChannelInternal); 168 internalChannel.tlsFlags = tlsFlags; 169 return new Promise(resolve => { 170 req.onload = () => { 171 ok( 172 expectSuccess, 173 `should ${expectSuccess ? "" : "not "}have gotten load event` 174 ); 175 equal(req.responseText, "OK", "response text should be 'OK'"); 176 resolve(); 177 }; 178 req.onerror = () => { 179 ok( 180 !expectSuccess, 181 `should ${!expectSuccess ? "" : "not "}have gotten an error` 182 ); 183 resolve(); 184 }; 185 186 req.send(); 187 }); 188 } 189 190 add_task(async function () { 191 Services.prefs.setIntPref("security.tls.version.max", 4); 192 Services.prefs.setCharPref("network.dns.localDomains", hostname); 193 let cert = getTestServerCertificate(); 194 195 // server that accepts 1.1->1.3 and a client max 1.3. expect 1.3 196 info("TEST 1"); 197 let server = startServer( 198 cert, 199 Ci.nsITLSClientStatus.TLS_VERSION_1_1, 200 Ci.nsITLSClientStatus.TLS_VERSION_1_3, 201 Ci.nsITLSClientStatus.TLS_VERSION_1_3 202 ); 203 storeCertOverride(server.port, cert); 204 await startClient(server.port, 4, true /*should succeed*/); 205 server.close(); 206 207 // server that accepts 1.1->1.3 and a client max 1.1. expect 1.1 208 info("TEST 2"); 209 server = startServer( 210 cert, 211 Ci.nsITLSClientStatus.TLS_VERSION_1_1, 212 Ci.nsITLSClientStatus.TLS_VERSION_1_3, 213 Ci.nsITLSClientStatus.TLS_VERSION_1_1 214 ); 215 storeCertOverride(server.port, cert); 216 await startClient(server.port, 2, true); 217 server.close(); 218 219 // server that accepts 1.2->1.2 and a client max 1.3. expect 1.2 220 info("TEST 3"); 221 server = startServer( 222 cert, 223 Ci.nsITLSClientStatus.TLS_VERSION_1_2, 224 Ci.nsITLSClientStatus.TLS_VERSION_1_2, 225 Ci.nsITLSClientStatus.TLS_VERSION_1_2 226 ); 227 storeCertOverride(server.port, cert); 228 await startClient(server.port, 4, true); 229 server.close(); 230 231 // server that accepts 1.2->1.2 and a client max 1.1. expect fail 232 info("TEST 4"); 233 server = startServer( 234 cert, 235 Ci.nsITLSClientStatus.TLS_VERSION_1_2, 236 Ci.nsITLSClientStatus.TLS_VERSION_1_2, 237 0 238 ); 239 storeCertOverride(server.port, cert); 240 await startClient(server.port, 2, false); 241 242 server.close(); 243 }); 244 245 registerCleanupFunction(function () { 246 Services.prefs.clearUserPref("security.tls.version.max"); 247 Services.prefs.clearUserPref("network.dns.localDomains"); 248 });