summaryrefslogtreecommitdiffstats
path: root/devtools/shared/security/tests/xpcshell
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/shared/security/tests/xpcshell/.eslintrc.js6
-rw-r--r--devtools/shared/security/tests/xpcshell/head_dbg.js95
-rw-r--r--devtools/shared/security/tests/xpcshell/test_encryption.js106
-rw-r--r--devtools/shared/security/tests/xpcshell/test_oob_cert_auth.js267
-rw-r--r--devtools/shared/security/tests/xpcshell/testactors.js16
-rw-r--r--devtools/shared/security/tests/xpcshell/xpcshell.ini11
6 files changed, 501 insertions, 0 deletions
diff --git a/devtools/shared/security/tests/xpcshell/.eslintrc.js b/devtools/shared/security/tests/xpcshell/.eslintrc.js
new file mode 100644
index 0000000000..8611c174f5
--- /dev/null
+++ b/devtools/shared/security/tests/xpcshell/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the common devtools xpcshell eslintrc config.
+ extends: "../../../../.eslintrc.xpcshell.js",
+};
diff --git a/devtools/shared/security/tests/xpcshell/head_dbg.js b/devtools/shared/security/tests/xpcshell/head_dbg.js
new file mode 100644
index 0000000000..6adf9bdd1b
--- /dev/null
+++ b/devtools/shared/security/tests/xpcshell/head_dbg.js
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* exported defer, DevToolsClient, initTestDevToolsServer */
+
+const { loader, require } = ChromeUtils.import(
+ "resource://devtools/shared/Loader.jsm"
+);
+const defer = require("devtools/shared/defer");
+const Services = require("Services");
+const xpcInspector = require("xpcInspector");
+const { DevToolsServer } = require("devtools/server/devtools-server");
+const { DevToolsClient } = require("devtools/client/devtools-client");
+// We need to require lazily since will be crashed if we load SocketListener too early
+// in xpc shell test due to SocketListener loads PSM module.
+loader.lazyRequireGetter(
+ this,
+ "SocketListener",
+ "devtools/shared/security/socket",
+ true
+);
+
+// We do not want to log packets by default, because in some tests,
+// we can be sending large amounts of data. The test harness has
+// trouble dealing with logging all the data, and we end up with
+// intermittent time outs (e.g. bug 775924).
+// Services.prefs.setBoolPref("devtools.debugger.log", true);
+// Services.prefs.setBoolPref("devtools.debugger.log.verbose", true);
+// Enable remote debugging for the relevant tests.
+Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
+// Fast timeout for TLS tests
+Services.prefs.setIntPref("devtools.remote.tls-handshake-timeout", 1000);
+
+// Convert an nsIScriptError 'logLevel' value into an appropriate string.
+function scriptErrorLogLevel(message) {
+ switch (message.logLevel) {
+ case Ci.nsIConsoleMessage.info:
+ return "info";
+ case Ci.nsIConsoleMessage.warn:
+ return "warning";
+ default:
+ Assert.equal(message.logLevel, Ci.nsIConsoleMessage.error);
+ return "error";
+ }
+}
+
+// Register a console listener, so console messages don't just disappear
+// into the ether.
+var listener = {
+ observe: function(message) {
+ let string;
+ try {
+ message.QueryInterface(Ci.nsIScriptError);
+ dump(
+ message.sourceName +
+ ":" +
+ message.lineNumber +
+ ": " +
+ scriptErrorLogLevel(message) +
+ ": " +
+ message.errorMessage +
+ "\n"
+ );
+ string = message.errorMessage;
+ } catch (ex) {
+ // Be a little paranoid with message, as the whole goal here is to lose
+ // no information.
+ try {
+ string = "" + message.message;
+ } catch (e) {
+ string = "<error converting error message to string>";
+ }
+ }
+
+ // Make sure we exit all nested event loops so that the test can finish.
+ while (xpcInspector.eventLoopNestLevel > 0) {
+ xpcInspector.exitNestedEventLoop();
+ }
+
+ info("head_dbg.js got console message: " + string + "\n");
+ },
+};
+
+Services.console.registerListener(listener);
+
+/**
+ * Initialize the testing devtools server.
+ */
+function initTestDevToolsServer() {
+ const { createRootActor } = require("xpcshell-test/testactors");
+ DevToolsServer.setRootActor(createRootActor);
+ DevToolsServer.init();
+}
diff --git a/devtools/shared/security/tests/xpcshell/test_encryption.js b/devtools/shared/security/tests/xpcshell/test_encryption.js
new file mode 100644
index 0000000000..1721418a5b
--- /dev/null
+++ b/devtools/shared/security/tests/xpcshell/test_encryption.js
@@ -0,0 +1,106 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test basic functionality of DevTools client and server TLS encryption mode
+function run_test() {
+ // Need profile dir to store the key / cert
+ do_get_profile();
+ // Ensure PSM is initialized
+ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+ run_next_test();
+}
+
+function connectClient(client) {
+ return client.connect();
+}
+
+add_task(async function() {
+ initTestDevToolsServer();
+});
+
+// Client w/ encryption connects successfully to server w/ encryption
+add_task(async function() {
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ const AuthenticatorType = DevToolsServer.Authenticators.get("PROMPT");
+ const authenticator = new AuthenticatorType.Server();
+ authenticator.allowConnection = () => {
+ return DevToolsServer.AuthenticationResult.ALLOW;
+ };
+
+ const socketOptions = {
+ authenticator,
+ encryption: true,
+ portOrPath: -1,
+ };
+ const listener = new SocketListener(DevToolsServer, socketOptions);
+ ok(listener, "Socket listener created");
+ await listener.open();
+ equal(DevToolsServer.listeningSockets, 1, "1 listening socket");
+
+ const transport = await DevToolsClient.socketConnect({
+ host: "127.0.0.1",
+ port: listener.port,
+ encryption: true,
+ });
+ ok(transport, "Client transport created");
+
+ const client = new DevToolsClient(transport);
+ const onUnexpectedClose = () => {
+ do_throw("Closed unexpectedly");
+ };
+ client.on("closed", onUnexpectedClose);
+ await connectClient(client);
+
+ // Send a message the server will echo back
+ const message = "secrets";
+ const reply = await client.mainRoot.echo({ message });
+ equal(reply.message, message, "Encrypted echo matches");
+
+ client.off("closed", onUnexpectedClose);
+ transport.close();
+ listener.close();
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+});
+
+// Client w/o encryption fails to connect to server w/ encryption
+add_task(async function() {
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ const AuthenticatorType = DevToolsServer.Authenticators.get("PROMPT");
+ const authenticator = new AuthenticatorType.Server();
+ authenticator.allowConnection = () => {
+ return DevToolsServer.AuthenticationResult.ALLOW;
+ };
+
+ const socketOptions = {
+ authenticator,
+ encryption: true,
+ portOrPath: -1,
+ };
+ const listener = new SocketListener(DevToolsServer, socketOptions);
+ ok(listener, "Socket listener created");
+ await listener.open();
+ equal(DevToolsServer.listeningSockets, 1, "1 listening socket");
+
+ try {
+ await DevToolsClient.socketConnect({
+ host: "127.0.0.1",
+ port: listener.port,
+ // encryption: false is the default
+ });
+ } catch (e) {
+ ok(true, "Client failed to connect as expected");
+ listener.close();
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+ return;
+ }
+
+ do_throw("Connection unexpectedly succeeded");
+});
+
+add_task(async function() {
+ DevToolsServer.destroy();
+});
diff --git a/devtools/shared/security/tests/xpcshell/test_oob_cert_auth.js b/devtools/shared/security/tests/xpcshell/test_oob_cert_auth.js
new file mode 100644
index 0000000000..229db1e62f
--- /dev/null
+++ b/devtools/shared/security/tests/xpcshell/test_oob_cert_auth.js
@@ -0,0 +1,267 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const cert = require("devtools/shared/security/cert");
+
+// Test basic functionality of DevTools client and server OOB_CERT auth (used
+// with WiFi debugging)
+function run_test() {
+ // Need profile dir to store the key / cert
+ do_get_profile();
+ // Ensure PSM is initialized
+ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
+ run_next_test();
+}
+
+function connectClient(client) {
+ return client.connect();
+}
+
+add_task(async function() {
+ initTestDevToolsServer();
+});
+
+// Client w/ OOB_CERT auth connects successfully to server w/ OOB_CERT auth
+add_task(async function() {
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ // Grab our cert, instead of relying on a discovery advertisement
+ const serverCert = await cert.local.getOrCreate();
+
+ const oobData = defer();
+ const AuthenticatorType = DevToolsServer.Authenticators.get("OOB_CERT");
+ const serverAuth = new AuthenticatorType.Server();
+ serverAuth.allowConnection = () => {
+ return DevToolsServer.AuthenticationResult.ALLOW;
+ };
+ // Skip prompt for tests
+ serverAuth.receiveOOB = () => oobData.promise;
+
+ const socketOptions = {
+ authenticator: serverAuth,
+ encryption: true,
+ portOrPath: -1,
+ };
+ const listener = new SocketListener(DevToolsServer, socketOptions);
+ ok(listener, "Socket listener created");
+ await listener.open();
+ equal(DevToolsServer.listeningSockets, 1, "1 listening socket");
+
+ const clientAuth = new AuthenticatorType.Client();
+ clientAuth.sendOOB = ({ oob }) => {
+ info(oob);
+ // Pass to server, skipping prompt for tests
+ oobData.resolve(oob);
+ };
+
+ const transport = await DevToolsClient.socketConnect({
+ host: "127.0.0.1",
+ port: listener.port,
+ encryption: true,
+ authenticator: clientAuth,
+ cert: {
+ sha256: serverCert.sha256Fingerprint,
+ },
+ });
+ ok(transport, "Client transport created");
+
+ const client = new DevToolsClient(transport);
+ const onUnexpectedClose = () => {
+ do_throw("Closed unexpectedly");
+ };
+ client.on("closed", onUnexpectedClose);
+ await connectClient(client);
+
+ // Send a message the server will echo back
+ const message = "secrets";
+ const reply = await client.mainRoot.echo({ message });
+ equal(reply.message, message, "Encrypted echo matches");
+
+ client.off("closed", onUnexpectedClose);
+ transport.close();
+ listener.close();
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+});
+
+// Client w/o OOB_CERT auth fails to connect to server w/ OOB_CERT auth
+add_task(async function() {
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ const oobData = defer();
+ const AuthenticatorType = DevToolsServer.Authenticators.get("OOB_CERT");
+ const serverAuth = new AuthenticatorType.Server();
+ serverAuth.allowConnection = () => {
+ return DevToolsServer.AuthenticationResult.ALLOW;
+ };
+ // Skip prompt for tests
+ serverAuth.receiveOOB = () => oobData.promise;
+
+ const socketOptions = {
+ authenticator: serverAuth,
+ encryption: true,
+ portOrPath: -1,
+ };
+ const listener = new SocketListener(DevToolsServer, socketOptions);
+ ok(listener, "Socket listener created");
+ await listener.open();
+ equal(DevToolsServer.listeningSockets, 1, "1 listening socket");
+
+ // This will succeed, but leaves the client in confused state, and no data is
+ // actually accessible
+ const transport = await DevToolsClient.socketConnect({
+ host: "127.0.0.1",
+ port: listener.port,
+ encryption: true,
+ // authenticator: PROMPT is the default
+ });
+
+ // Attempt to use the transport
+ const deferred = defer();
+ const client = new DevToolsClient(transport);
+ client.onPacket = packet => {
+ // Client did not authenticate, so it ends up seeing the server's auth data
+ // which is effectively malformed data from the client's perspective
+ ok(!packet.from && packet.authResult, "Got auth packet instead of data");
+ deferred.resolve();
+ };
+ client.connect();
+ await deferred.promise;
+
+ // Try to send a message the server will echo back
+ const message = "secrets";
+ try {
+ await client.request({
+ to: "root",
+ type: "echo",
+ message,
+ });
+ } catch (e) {
+ ok(true, "Sending a message failed");
+ transport.close();
+ listener.close();
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+ return;
+ }
+
+ do_throw("Connection unexpectedly succeeded");
+});
+
+// Client w/ invalid K value fails to connect
+add_task(async function() {
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ // Grab our cert, instead of relying on a discovery advertisement
+ const serverCert = await cert.local.getOrCreate();
+
+ const oobData = defer();
+ const AuthenticatorType = DevToolsServer.Authenticators.get("OOB_CERT");
+ const serverAuth = new AuthenticatorType.Server();
+ serverAuth.allowConnection = () => {
+ return DevToolsServer.AuthenticationResult.ALLOW;
+ };
+ // Skip prompt for tests
+ serverAuth.receiveOOB = () => oobData.promise;
+
+ const clientAuth = new AuthenticatorType.Client();
+ clientAuth.sendOOB = ({ oob }) => {
+ info(oob);
+ info("Modifying K value, should fail");
+ // Pass to server, skipping prompt for tests
+ oobData.resolve({
+ k: oob.k + 1,
+ sha256: oob.sha256,
+ });
+ };
+
+ const socketOptions = {
+ authenticator: serverAuth,
+ encryption: true,
+ portOrPath: -1,
+ };
+ const listener = new SocketListener(DevToolsServer, socketOptions);
+ ok(listener, "Socket listener created");
+ await listener.open();
+ equal(DevToolsServer.listeningSockets, 1, "1 listening socket");
+
+ try {
+ await DevToolsClient.socketConnect({
+ host: "127.0.0.1",
+ port: listener.port,
+ encryption: true,
+ authenticator: clientAuth,
+ cert: {
+ sha256: serverCert.sha256Fingerprint,
+ },
+ });
+ } catch (e) {
+ ok(true, "Client failed to connect as expected");
+ listener.close();
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+ return;
+ }
+
+ do_throw("Connection unexpectedly succeeded");
+});
+
+// Client w/ invalid cert hash fails to connect
+add_task(async function() {
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ // Grab our cert, instead of relying on a discovery advertisement
+ const serverCert = await cert.local.getOrCreate();
+
+ const oobData = defer();
+ const AuthenticatorType = DevToolsServer.Authenticators.get("OOB_CERT");
+ const serverAuth = new AuthenticatorType.Server();
+ serverAuth.allowConnection = () => {
+ return DevToolsServer.AuthenticationResult.ALLOW;
+ };
+ // Skip prompt for tests
+ serverAuth.receiveOOB = () => oobData.promise;
+
+ const clientAuth = new AuthenticatorType.Client();
+ clientAuth.sendOOB = ({ oob }) => {
+ info(oob);
+ info("Modifying cert hash, should fail");
+ // Pass to server, skipping prompt for tests
+ oobData.resolve({
+ k: oob.k,
+ sha256: oob.sha256 + 1,
+ });
+ };
+
+ const socketOptions = {
+ authenticator: serverAuth,
+ encryption: true,
+ portOrPath: -1,
+ };
+ const listener = new SocketListener(DevToolsServer, socketOptions);
+ ok(listener, "Socket listener created");
+ await listener.open();
+ equal(DevToolsServer.listeningSockets, 1, "1 listening socket");
+
+ try {
+ await DevToolsClient.socketConnect({
+ host: "127.0.0.1",
+ port: listener.port,
+ encryption: true,
+ authenticator: clientAuth,
+ cert: {
+ sha256: serverCert.sha256Fingerprint,
+ },
+ });
+ } catch (e) {
+ ok(true, "Client failed to connect as expected");
+ listener.close();
+ equal(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+ return;
+ }
+
+ do_throw("Connection unexpectedly succeeded");
+});
+
+add_task(async function() {
+ DevToolsServer.destroy();
+});
diff --git a/devtools/shared/security/tests/xpcshell/testactors.js b/devtools/shared/security/tests/xpcshell/testactors.js
new file mode 100644
index 0000000000..e5f849a431
--- /dev/null
+++ b/devtools/shared/security/tests/xpcshell/testactors.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const { RootActor } = require("devtools/server/actors/root");
+const {
+ ActorRegistry,
+} = require("devtools/server/actors/utils/actor-registry");
+
+exports.createRootActor = function createRootActor(connection) {
+ const root = new RootActor(connection, {
+ globalActorFactories: ActorRegistry.globalActorFactories,
+ });
+ root.applicationType = "xpcshell-tests";
+ return root;
+};
diff --git a/devtools/shared/security/tests/xpcshell/xpcshell.ini b/devtools/shared/security/tests/xpcshell/xpcshell.ini
new file mode 100644
index 0000000000..c1a669c228
--- /dev/null
+++ b/devtools/shared/security/tests/xpcshell/xpcshell.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+tags = devtools
+head = head_dbg.js
+skip-if = toolkit == 'android' || socketprocess_networking
+firefox-appdir = browser
+
+support-files=
+ testactors.js
+
+[test_encryption.js]
+[test_oob_cert_auth.js]