bug 1273677 - ensure session cache is properly configured and torn down for TLSServerSocket r=mcmanus

MozReview-Commit-ID: 6i7HxTdLcID

--HG--
extra : rebase_source : 3c1b4c0ed798c166cbc2bcad71de90543af176c1
This commit is contained in:
David Keeler 2016-05-23 13:58:56 -07:00
parent e8fd20fdcf
commit e87f6f88e2
4 changed files with 159 additions and 0 deletions

View File

@ -690,6 +690,7 @@ SSL_SetSockPeerID
SSL_SetSRTPCiphers
SSL_SetStapledOCSPResponses
SSL_SetURL
SSL_ShutdownServerSessionIDCache
SSL_SNISocketConfigHook
SSL_VersionRangeGet
SSL_VersionRangeGetDefault

View File

@ -0,0 +1,141 @@
/* 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.setSessionCache(true);
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);
});

View File

@ -336,6 +336,9 @@ skip-if = os != "win"
# The local cert service used by this test is not currently shipped on Android
skip-if = os == "android"
firefox-appdir = browser
[test_tls_server_multiple_clients.js]
# The local cert service used by this test is not currently shipped on Android
skip-if = os == "android"
[test_1073747.js]
[test_multipart_streamconv_application_package.js]
[test_safeoutputstream_append.js]

View File

@ -1591,6 +1591,17 @@ nsNSSComponent::InitializeNSS()
return NS_ERROR_FAILURE;
}
// TLSServerSocket may be run with the session cache enabled. It is necessary
// to call this once before that can happen. This specifies a maximum of 1000
// cache entries (the default number of cache entries is 10000, which seems a
// little excessive as there probably won't be that many clients connecting to
// any TLSServerSockets the browser runs.)
// Note that this must occur before any calls to SSL_ClearSessionCache
// (otherwise memory will leak).
if (SSL_ConfigServerSessionIDCache(1000, 0, 0, nullptr) != SECSuccess) {
return NS_ERROR_FAILURE;
}
// ensure the CertBlocklist is initialised
nsCOMPtr<nsICertBlocklist> certList = do_GetService(NS_CERTBLOCKLIST_CONTRACTID);
if (!certList) {
@ -1650,6 +1661,9 @@ nsNSSComponent::ShutdownNSS()
ShutdownSmartCardThreads();
#endif
SSL_ClearSessionCache();
// TLSServerSocket may be run with the session cache enabled. This ensures
// those resources are cleaned up.
Unused << SSL_ShutdownServerSessionIDCache();
UnloadLoadableRoots();
#ifndef MOZ_NO_EV_CERTS
CleanupIdentityInfo();