/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Need profile dir to store the key / cert do_get_profile(); // Ensure PSM is initialized Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports); const { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {}); const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); const certService = Cc["@mozilla.org/security/local-cert-service;1"] .getService(Ci.nsILocalCertService); const certOverrideService = Cc["@mozilla.org/security/certoverride;1"] .getService(Ci.nsICertOverrideService); const socketTransportService = Cc["@mozilla.org/network/socket-transport-service;1"] .getService(Ci.nsISocketTransportService); function run_test() { run_next_test(); } function getCert() { let deferred = promise.defer(); certService.getOrCreateCert("tls-test", { handleCert: function(c, rv) { if (rv) { deferred.reject(rv); return; } deferred.resolve(c); } }); return deferred.promise; } function startServer(cert) { let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"] .createInstance(Ci.nsITLSServerSocket); tlsServer.init(-1, true, -1); tlsServer.serverCert = cert; let input, output; let listener = { onSocketAccepted: function(socket, transport) { do_print("Accept TLS client connection"); let connectionInfo = transport.securityInfo .QueryInterface(Ci.nsITLSServerConnectionInfo); connectionInfo.setSecurityObserver(listener); input = transport.openInputStream(0, 0, 0); output = transport.openOutputStream(0, 0, 0); }, onHandshakeDone: function(socket, status) { do_print("TLS handshake done"); input.asyncWait({ onInputStreamReady: function(input) { NetUtil.asyncCopy(input, output); } }, 0, 0, Services.tm.currentThread); }, onStopListening: function() {} }; tlsServer.setSessionTickets(false); tlsServer.asyncListen(listener); return tlsServer.port; } function storeCertOverride(port, cert) { let overrideBits = Ci.nsICertOverrideService.ERROR_UNTRUSTED | Ci.nsICertOverrideService.ERROR_MISMATCH; certOverrideService.rememberValidityOverride("127.0.0.1", port, cert, overrideBits, true); } function startClient(port) { let transport = socketTransportService.createTransport(["ssl"], 1, "127.0.0.1", port, null); let input; let output; let inputDeferred = promise.defer(); let outputDeferred = promise.defer(); let handler = { onTransportStatus: function(transport, status) { if (status === Ci.nsISocketTransport.STATUS_CONNECTED_TO) { output.asyncWait(handler, 0, 0, Services.tm.currentThread); } }, onInputStreamReady: function(input) { try { let data = NetUtil.readInputStreamToString(input, input.available()); equal(data, "HELLO", "Echoed data received"); input.close(); output.close(); inputDeferred.resolve(); } catch (e) { inputDeferred.reject(e); } }, onOutputStreamReady: function(output) { try { output.write("HELLO", 5); do_print("Output to server written"); outputDeferred.resolve(); input = transport.openInputStream(0, 0, 0); input.asyncWait(handler, 0, 0, Services.tm.currentThread); } catch (e) { outputDeferred.reject(e); } } }; transport.setEventSink(handler, Services.tm.currentThread); output = transport.openOutputStream(0, 0, 0); return promise.all([inputDeferred.promise, outputDeferred.promise]); } add_task(function*() { let cert = yield getCert(); ok(!!cert, "Got self-signed cert"); let port = startServer(cert); storeCertOverride(port, cert); yield startClient(port); yield startClient(port); });