at 21.11-pre 5.3 kB view raw
1# Checks that `security.pki` options are working in curl and the main browser 2# engines: Gecko (via Firefox), Chromium, QtWebEngine (Falkon) and WebKitGTK 3# (via Midori). The test checks that certificates issued by a custom trusted 4# CA are accepted but those from an unknown CA are rejected. 5 6import ./make-test-python.nix ({ pkgs, lib, ... }: 7 8let 9 makeCert = { caName, domain }: pkgs.runCommand "example-cert" 10 { buildInputs = [ pkgs.gnutls ]; } 11 '' 12 mkdir $out 13 14 # CA cert template 15 cat >ca.template <<EOF 16 organization = "${caName}" 17 cn = "${caName}" 18 expiration_days = 365 19 ca 20 cert_signing_key 21 crl_signing_key 22 EOF 23 24 # server cert template 25 cat >server.template <<EOF 26 organization = "An example company" 27 cn = "${domain}" 28 expiration_days = 30 29 dns_name = "${domain}" 30 encryption_key 31 signing_key 32 EOF 33 34 # generate CA keypair 35 certtool \ 36 --generate-privkey \ 37 --key-type rsa \ 38 --sec-param High \ 39 --outfile $out/ca.key 40 certtool \ 41 --generate-self-signed \ 42 --load-privkey $out/ca.key \ 43 --template ca.template \ 44 --outfile $out/ca.crt 45 46 # generate server keypair 47 certtool \ 48 --generate-privkey \ 49 --key-type rsa \ 50 --sec-param High \ 51 --outfile $out/server.key 52 certtool \ 53 --generate-certificate \ 54 --load-privkey $out/server.key \ 55 --load-ca-privkey $out/ca.key \ 56 --load-ca-certificate $out/ca.crt \ 57 --template server.template \ 58 --outfile $out/server.crt 59 ''; 60 61 example-good-cert = makeCert 62 { caName = "Example good CA"; 63 domain = "good.example.com"; 64 }; 65 66 example-bad-cert = makeCert 67 { caName = "Unknown CA"; 68 domain = "bad.example.com"; 69 }; 70 71in 72 73{ 74 name = "custom-ca"; 75 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 76 77 enableOCR = true; 78 79 machine = { pkgs, ... }: 80 { imports = [ ./common/user-account.nix ./common/x11.nix ]; 81 82 # chromium-based browsers refuse to run as root 83 test-support.displayManager.auto.user = "alice"; 84 # browsers may hang with the default memory 85 virtualisation.memorySize = "500"; 86 87 networking.hosts."127.0.0.1" = [ "good.example.com" "bad.example.com" ]; 88 security.pki.certificateFiles = [ "${example-good-cert}/ca.crt" ]; 89 90 services.nginx.enable = true; 91 services.nginx.virtualHosts."good.example.com" = 92 { onlySSL = true; 93 sslCertificate = "${example-good-cert}/server.crt"; 94 sslCertificateKey = "${example-good-cert}/server.key"; 95 locations."/".extraConfig = '' 96 add_header Content-Type text/plain; 97 return 200 'It works!'; 98 ''; 99 }; 100 services.nginx.virtualHosts."bad.example.com" = 101 { onlySSL = true; 102 sslCertificate = "${example-bad-cert}/server.crt"; 103 sslCertificateKey = "${example-bad-cert}/server.key"; 104 locations."/".extraConfig = '' 105 add_header Content-Type text/plain; 106 return 200 'It does not work!'; 107 ''; 108 }; 109 110 environment.systemPackages = with pkgs; 111 [ xdotool firefox chromium falkon midori ]; 112 }; 113 114 testScript = '' 115 from typing import Tuple 116 def execute_as(user: str, cmd: str) -> Tuple[int, str]: 117 """ 118 Run a shell command as a specific user. 119 """ 120 return machine.execute(f"sudo -u {user} {cmd}") 121 122 123 def wait_for_window_as(user: str, cls: str) -> None: 124 """ 125 Wait until a X11 window of a given user appears. 126 """ 127 128 def window_is_visible(last_try: bool) -> bool: 129 ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}") 130 if last_try: 131 machine.log(f"Last chance to match {cls} on the window list") 132 return ret == 0 133 134 with machine.nested("Waiting for a window to appear"): 135 retry(window_is_visible) 136 137 138 machine.start() 139 140 with subtest("Good certificate is trusted in curl"): 141 machine.wait_for_unit("nginx") 142 machine.wait_for_open_port(443) 143 machine.succeed("curl -fv https://good.example.com") 144 145 with subtest("Unknown CA is untrusted in curl"): 146 machine.fail("curl -fv https://bad.example.com") 147 148 browsers = ["firefox", "chromium", "falkon", "midori"] 149 errors = ["Security Risk", "not private", "Certificate Error", "Security"] 150 151 machine.wait_for_x() 152 for browser, error in zip(browsers, errors): 153 with subtest("Good certificate is trusted in " + browser): 154 execute_as( 155 "alice", f"env P11_KIT_DEBUG=trust {browser} https://good.example.com & >&2" 156 ) 157 wait_for_window_as("alice", browser) 158 machine.wait_for_text("It works!") 159 machine.screenshot("good" + browser) 160 execute_as("alice", "xdotool key ctrl+w") # close tab 161 162 with subtest("Unknown CA is untrusted in " + browser): 163 execute_as("alice", f"{browser} https://bad.example.com & >&2") 164 machine.wait_for_text(error) 165 machine.screenshot("bad" + browser) 166 machine.succeed("pkill " + browser) 167 ''; 168})