From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../ssl/tests/unit/test_logoutAndTeardown.js | 192 +++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 security/manager/ssl/tests/unit/test_logoutAndTeardown.js (limited to 'security/manager/ssl/tests/unit/test_logoutAndTeardown.js') diff --git a/security/manager/ssl/tests/unit/test_logoutAndTeardown.js b/security/manager/ssl/tests/unit/test_logoutAndTeardown.js new file mode 100644 index 0000000000..1582978398 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_logoutAndTeardown.js @@ -0,0 +1,192 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ + +"use strict"; + +// This test ensures that in-progress https connections are cancelled when the +// user logs out of a PKCS#11 token. + +// Get a profile directory and ensure PSM initializes NSS. +do_get_profile(); +Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports); + +function getTestServerCertificate() { + const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService( + Ci.nsIX509CertDB + ); + const certFile = do_get_file("test_certDB_import/encrypted_with_aes.p12"); + certDB.importPKCS12File(certFile, "password"); + for (const cert of certDB.getCerts()) { + if (cert.commonName == "John Doe") { + return cert; + } + } + return null; +} + +class InputStreamCallback { + constructor(output) { + this.output = output; + this.stopped = false; + } + + onInputStreamReady(stream) { + info("input stream ready"); + if (this.stopped) { + info("input stream callback stopped - bailing"); + return; + } + let available = 0; + try { + available = stream.available(); + } catch (e) { + // onInputStreamReady may fire when the stream has been closed. + equal( + e.result, + Cr.NS_BASE_STREAM_CLOSED, + "error should be NS_BASE_STREAM_CLOSED" + ); + } + if (available > 0) { + let request = NetUtil.readInputStreamToString(stream, available, { + charset: "utf8", + }); + ok( + request.startsWith("GET / HTTP/1.1\r\n"), + "Should get a simple GET / HTTP/1.1 request" + ); + let response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\n"; + this.output.write(response, response.length); + // Keep writing a response until the client disconnects due to the + // logoutAndTeardown. If the client never disconnects, the test will time + // out, indicating a bug. + while (true) { + this.output.write("a", 1); + } + } + this.output.close(); + info("done with input stream ready"); + } + + stop() { + this.stopped = true; + this.output.close(); + } +} + +class TLSServerSecurityObserver { + constructor(input, output) { + this.input = input; + this.output = output; + this.callbacks = []; + this.stopped = false; + } + + onHandshakeDone(socket, status) { + info("TLS handshake done"); + info(`TLS version used: ${status.tlsVersionUsed}`); + + if (this.stopped) { + info("handshake done callback stopped - bailing"); + return; + } + + let callback = new InputStreamCallback(this.output); + this.callbacks.push(callback); + this.input.asyncWait(callback, 0, 0, Services.tm.currentThread); + + // We've set up everything needed for a successful request/response, + // but calling logoutAndTeardown should cause the request to be cancelled. + Cc["@mozilla.org/security/sdr;1"] + .getService(Ci.nsISecretDecoderRing) + .logoutAndTeardown(); + } + + stop() { + this.stopped = true; + this.input.close(); + this.output.close(); + this.callbacks.forEach(callback => { + callback.stop(); + }); + } +} + +class ServerSocketListener { + constructor() { + this.securityObservers = []; + } + + onSocketAccepted(socket, transport) { + info("accepted TLS client connection"); + let connectionInfo = transport.securityCallbacks.getInterface( + Ci.nsITLSServerConnectionInfo + ); + let input = transport.openInputStream(0, 0, 0); + let output = transport.openOutputStream(0, 0, 0); + let securityObserver = new TLSServerSecurityObserver(input, output); + this.securityObservers.push(securityObserver); + connectionInfo.setSecurityObserver(securityObserver); + } + + // For some reason we get input stream callback events after we've stopped + // listening, so this ensures we just drop those events. + onStopListening() { + info("onStopListening"); + this.securityObservers.forEach(observer => { + observer.stop(); + }); + } +} + +function getStartedServer(cert) { + let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance( + Ci.nsITLSServerSocket + ); + tlsServer.init(-1, true, -1); + tlsServer.serverCert = cert; + tlsServer.setSessionTickets(false); + tlsServer.asyncListen(new ServerSocketListener()); + return tlsServer; +} + +const hostname = "example.com"; + +function storeCertOverride(port, cert) { + let certOverrideService = Cc[ + "@mozilla.org/security/certoverride;1" + ].getService(Ci.nsICertOverrideService); + certOverrideService.rememberValidityOverride(hostname, port, {}, cert, true); +} + +function startClient(port) { + let req = new XMLHttpRequest(); + req.open("GET", `https://${hostname}:${port}`); + return new Promise((resolve, reject) => { + req.onload = () => { + ok(false, "should not have gotten load event"); + resolve(); + }; + req.onerror = () => { + ok(true, "should have gotten an error"); + resolve(); + }; + + req.send(); + }); +} + +add_task(async function () { + Services.prefs.setCharPref("network.dns.localDomains", hostname); + let cert = getTestServerCertificate(); + + let server = getStartedServer(cert); + storeCertOverride(server.port, cert); + await startClient(server.port); + server.close(); +}); + +registerCleanupFunction(function () { + Services.prefs.clearUserPref("network.dns.localDomains"); +}); -- cgit v1.2.3