at 22.05-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 85 networking.hosts."127.0.0.1" = [ "good.example.com" "bad.example.com" ]; 86 security.pki.certificateFiles = [ "${example-good-cert}/ca.crt" ]; 87 88 services.nginx.enable = true; 89 services.nginx.virtualHosts."good.example.com" = 90 { onlySSL = true; 91 sslCertificate = "${example-good-cert}/server.crt"; 92 sslCertificateKey = "${example-good-cert}/server.key"; 93 locations."/".extraConfig = '' 94 add_header Content-Type text/plain; 95 return 200 'It works!'; 96 ''; 97 }; 98 services.nginx.virtualHosts."bad.example.com" = 99 { onlySSL = true; 100 sslCertificate = "${example-bad-cert}/server.crt"; 101 sslCertificateKey = "${example-bad-cert}/server.key"; 102 locations."/".extraConfig = '' 103 add_header Content-Type text/plain; 104 return 200 'It does not work!'; 105 ''; 106 }; 107 108 environment.systemPackages = with pkgs; [ 109 xdotool 110 firefox 111 chromium 112 qutebrowser 113 midori 114 ]; 115 }; 116 117 testScript = '' 118 from typing import Tuple 119 def execute_as(user: str, cmd: str) -> Tuple[int, str]: 120 """ 121 Run a shell command as a specific user. 122 """ 123 return machine.execute(f"sudo -u {user} {cmd}") 124 125 126 def wait_for_window_as(user: str, cls: str) -> None: 127 """ 128 Wait until a X11 window of a given user appears. 129 """ 130 131 def window_is_visible(last_try: bool) -> bool: 132 ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}") 133 if last_try: 134 machine.log(f"Last chance to match {cls} on the window list") 135 return ret == 0 136 137 with machine.nested("Waiting for a window to appear"): 138 retry(window_is_visible) 139 140 141 machine.start() 142 143 with subtest("Good certificate is trusted in curl"): 144 machine.wait_for_unit("nginx") 145 machine.wait_for_open_port(443) 146 machine.succeed("curl -fv https://good.example.com") 147 148 with subtest("Unknown CA is untrusted in curl"): 149 machine.fail("curl -fv https://bad.example.com") 150 151 browsers = { 152 "firefox": "Security Risk", 153 "chromium": "not private", 154 "qutebrowser -T": "Certificate error", 155 "midori": "Security" 156 } 157 158 machine.wait_for_x() 159 for command, error in browsers.items(): 160 browser = command.split()[0] 161 with subtest("Good certificate is trusted in " + browser): 162 execute_as( 163 "alice", f"env P11_KIT_DEBUG=trust {command} https://good.example.com & >&2" 164 ) 165 wait_for_window_as("alice", browser) 166 machine.wait_for_text("It works!") 167 machine.screenshot("good" + browser) 168 execute_as("alice", "xdotool key ctrl+w") # close tab 169 170 with subtest("Unknown CA is untrusted in " + browser): 171 execute_as("alice", f"{command} https://bad.example.com & >&2") 172 machine.wait_for_text(error) 173 machine.screenshot("bad" + browser) 174 machine.succeed("pkill " + browser) 175 ''; 176})