summaryrefslogtreecommitdiffstats
path: root/nixos/tests/custom-ca.nix
diff options
context:
space:
mode:
authorrnhmjoj <rnhmjoj@inventati.org>2021-01-10 18:28:29 +0100
committerrnhmjoj <rnhmjoj@inventati.org>2021-01-24 10:50:56 +0100
commitcc8a4227c1bf3638a7997cd5772b2d08ef2d903b (patch)
tree378eddf2f4551fa8f95bce24bcbb09c9e393c9a9 /nixos/tests/custom-ca.nix
parentb9bb98cf49c24b94a66d38630661b3249ac8ae19 (diff)
nixos/tests/custom-ca: init
This is a NixOS test for the security.pki options.
Diffstat (limited to 'nixos/tests/custom-ca.nix')
-rw-r--r--nixos/tests/custom-ca.nix161
1 files changed, 161 insertions, 0 deletions
diff --git a/nixos/tests/custom-ca.nix b/nixos/tests/custom-ca.nix
new file mode 100644
index 000000000000..67f7b3ff1f16
--- /dev/null
+++ b/nixos/tests/custom-ca.nix
@@ -0,0 +1,161 @@
+# Checks that `security.pki` options are working in curl and the main browser
+# engines: Gecko (via Firefox), Chromium, QtWebEngine (Falkon) and WebKitGTK
+# (via Midori). The test checks that certificates issued by a custom trusted
+# CA are accepted but those from an unknown CA are rejected.
+
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+
+let
+ makeCert = { caName, domain }: pkgs.runCommand "example-cert"
+ { buildInputs = [ pkgs.gnutls ]; }
+ ''
+ mkdir $out
+
+ # CA cert template
+ cat >ca.template <<EOF
+ organization = "${caName}"
+ cn = "${caName}"
+ expiration_days = 365
+ ca
+ cert_signing_key
+ crl_signing_key
+ EOF
+
+ # server cert template
+ cat >server.template <<EOF
+ organization = "An example company"
+ cn = "${domain}"
+ expiration_days = 30
+ dns_name = "${domain}"
+ encryption_key
+ signing_key
+ EOF
+
+ # generate CA keypair
+ certtool \
+ --generate-privkey \
+ --key-type rsa \
+ --sec-param High \
+ --outfile $out/ca.key
+ certtool \
+ --generate-self-signed \
+ --load-privkey $out/ca.key \
+ --template ca.template \
+ --outfile $out/ca.crt
+
+ # generate server keypair
+ certtool \
+ --generate-privkey \
+ --key-type rsa \
+ --sec-param High \
+ --outfile $out/server.key
+ certtool \
+ --generate-certificate \
+ --load-privkey $out/server.key \
+ --load-ca-privkey $out/ca.key \
+ --load-ca-certificate $out/ca.crt \
+ --template server.template \
+ --outfile $out/server.crt
+ '';
+
+ example-good-cert = makeCert
+ { caName = "Example good CA";
+ domain = "good.example.com";
+ };
+
+ example-bad-cert = makeCert
+ { caName = "Unknown CA";
+ domain = "bad.example.com";
+ };
+
+in
+
+{
+ name = "custom-ca";
+ meta.maintainers = with lib.maintainers; [ rnhmjoj ];
+
+ enableOCR = true;
+
+ machine = { pkgs, ... }:
+ { imports = [ ./common/user-account.nix ./common/x11.nix ];
+
+ # chromium-based browsers refuse to run as root
+ test-support.displayManager.auto.user = "alice";
+ # browsers may hang with the default memory
+ virtualisation.memorySize = "500";
+
+ networking.hosts."127.0.0.1" = [ "good.example.com" "bad.example.com" ];
+ security.pki.certificateFiles = [ "${example-good-cert}/ca.crt" ];
+
+ services.nginx.enable = true;
+ services.nginx.virtualHosts."good.example.com" =
+ { onlySSL = true;
+ sslCertificate = "${example-good-cert}/server.crt";
+ sslCertificateKey = "${example-good-cert}/server.key";
+ locations."/".extraConfig = "return 200 'It works!';";
+ };
+ services.nginx.virtualHosts."bad.example.com" =
+ { onlySSL = true;
+ sslCertificate = "${example-bad-cert}/server.crt";
+ sslCertificateKey = "${example-bad-cert}/server.key";
+ locations."/".extraConfig = "return 200 'It does not work!';";
+ };
+
+ environment.systemPackages = with pkgs;
+ [ xdotool firefox chromium falkon midori ];
+ };
+
+ testScript = ''
+ def execute_as(user: str, cmd: str) -> Tuple[int, str]:
+ """
+ Run a shell command as a specific user.
+ """
+ return machine.execute(f"sudo -u {user} {cmd}")
+
+
+ def wait_for_window_as(user: str, cls: str) -> None:
+ """
+ Wait until a X11 window of a given user appears.
+ """
+
+ def window_is_visible(last_try: bool) -> bool:
+ ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}")
+ if last_try:
+ machine.log(f"Last chance to match {cls} on the window list")
+ return ret == 0
+
+ with machine.nested("Waiting for a window to appear"):
+ retry(window_is_visible)
+
+
+ machine.start()
+
+ with subtest("Good certificate is trusted in curl"):
+ machine.wait_for_unit("nginx")
+ machine.wait_for_open_port(443)
+ machine.succeed("curl -fv https://good.example.com")
+
+ with subtest("Unknown CA is untrusted in curl"):
+ machine.fail("curl -fv https://bad.example.com")
+
+ browsers = ["firefox", "chromium", "falkon", "midori"]
+ errors = ["Security Risk", "not private", "Certificate Error", "Security"]
+
+ machine.wait_for_x()
+ for browser, error in zip(browsers, errors):
+ with subtest("Good certificate is trusted in " + browser):
+ execute_as(
+ "alice", f"env P11_KIT_DEBUG=trust {browser} https://good.example.com & >&2"
+ )
+ wait_for_window_as("alice", browser)
+ machine.wait_for_text("It works!")
+ machine.screenshot("good" + browser)
+ execute_as("alice", "xdotool key ctrl+w") # close tab
+
+ with subtest("Unknown CA is untrusted in " + browser):
+ execute_as("alice", f"{browser} https://bad.example.com & >&2")
+ machine.wait_for_text(error)
+ machine.screenshot("bad" + browser)
+ machine.succeed("pkill " + browser)
+ '';
+})