summaryrefslogtreecommitdiffstats
path: root/devtools/shared/security/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /devtools/shared/security/tests
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--devtools/shared/security/tests/chrome/.eslintrc.js6
-rw-r--r--devtools/shared/security/tests/chrome/chrome.ini4
-rw-r--r--devtools/shared/security/tests/chrome/test_websocket-transport.html74
-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
9 files changed, 585 insertions, 0 deletions
diff --git a/devtools/shared/security/tests/chrome/.eslintrc.js b/devtools/shared/security/tests/chrome/.eslintrc.js
new file mode 100644
index 0000000000..660a3bf0a9
--- /dev/null
+++ b/devtools/shared/security/tests/chrome/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ extends: "plugin:mozilla/chrome-test",
+};
diff --git a/devtools/shared/security/tests/chrome/chrome.ini b/devtools/shared/security/tests/chrome/chrome.ini
new file mode 100644
index 0000000000..5812511032
--- /dev/null
+++ b/devtools/shared/security/tests/chrome/chrome.ini
@@ -0,0 +1,4 @@
+[DEFAULT]
+tags = devtools
+
+[test_websocket-transport.html]
diff --git a/devtools/shared/security/tests/chrome/test_websocket-transport.html b/devtools/shared/security/tests/chrome/test_websocket-transport.html
new file mode 100644
index 0000000000..25174a7174
--- /dev/null
+++ b/devtools/shared/security/tests/chrome/test_websocket-transport.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test the WebSocket debugger transport</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<script>
+"use strict";
+
+window.onload = function() {
+ const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
+ const Services = require("Services");
+ // eslint-disable-next-line mozilla/reject-some-requires
+ const {DevToolsClient} = require("devtools/client/devtools-client");
+ const {DevToolsServer} = require("devtools/server/devtools-server");
+ const { SocketListener } = require("devtools/shared/security/socket");
+
+ Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
+ Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false);
+
+ SimpleTest.registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("devtools.debugger.remote-enabled");
+ Services.prefs.clearUserPref("devtools.debugger.prompt-connection");
+ });
+
+ add_task(async function() {
+ DevToolsServer.init();
+ DevToolsServer.registerAllActors();
+
+ is(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ const socketOptions = {
+ portOrPath: -1,
+ webSocket: true,
+ };
+ const listener = new SocketListener(DevToolsServer, socketOptions);
+ ok(listener, "Socket listener created");
+ await listener.open();
+ is(DevToolsServer.listeningSockets, 1, "1 listening socket");
+
+ const transport = await DevToolsClient.socketConnect({
+ host: "127.0.0.1",
+ port: listener.port,
+ webSocket: true,
+ });
+ ok(transport, "Client transport created");
+
+ const client = new DevToolsClient(transport);
+ const onUnexpectedClose = () => {
+ ok(false, "Closed unexpectedly");
+ };
+ client.on("closed", onUnexpectedClose);
+
+ await client.connect();
+
+ // Send a message the server that will echo back
+ const message = "message";
+ const reply = await client.mainRoot.echo({ message });
+ is(reply.message, message, "Echo message matches");
+
+ client.off("closed", onUnexpectedClose);
+ transport.close();
+ listener.close();
+ is(DevToolsServer.listeningSockets, 0, "0 listening sockets");
+
+ DevToolsServer.destroy();
+ });
+};
+</script>
+</body>
+</html>
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]