at 23.11-pre 4.5 kB view raw
1import ./make-test-python.nix ({ pkgs, lib, ...}: 2 3{ 4 name = "gnupg"; 5 meta = with lib.maintainers; { 6 maintainers = [ rnhmjoj ]; 7 }; 8 9 # server for testing SSH 10 nodes.server = { ... }: { 11 imports = [ ../modules/profiles/minimal.nix ]; 12 13 users.users.alice.isNormalUser = true; 14 services.openssh.enable = true; 15 }; 16 17 # machine for testing GnuPG 18 nodes.machine = { pkgs, ... }: { 19 imports = [ ../modules/profiles/minimal.nix ]; 20 21 users.users.alice.isNormalUser = true; 22 services.getty.autologinUser = "alice"; 23 24 environment.shellInit = '' 25 # preset a key passphrase in gpg-agent 26 preset_key() { 27 # find all keys 28 case "$1" in 29 ssh) grips=$(awk '/^[0-9A-F]/{print $1}' "''${GNUPGHOME:-$HOME/.gnupg}/sshcontrol") ;; 30 pgp) grips=$(gpg --with-keygrip --list-secret-keys | awk '/Keygrip/{print $3}') ;; 31 esac 32 33 # try to preset the passphrase for each key found 34 for grip in $grips; do 35 "$(gpgconf --list-dirs libexecdir)/gpg-preset-passphrase" -c -P "$2" "$grip" 36 done 37 } 38 ''; 39 40 programs.gnupg.agent.enable = true; 41 programs.gnupg.agent.enableSSHSupport = true; 42 }; 43 44 testScript = 45 '' 46 import shlex 47 48 49 def as_alice(command: str) -> str: 50 """ 51 Wraps a command to run it as Alice in a login shell 52 """ 53 quoted = shlex.quote(command) 54 return "su --login alice --command " + quoted 55 56 57 start_all() 58 59 with subtest("Wait for the autologin"): 60 machine.wait_until_tty_matches("1", "alice@machine") 61 62 with subtest("Can generate a PGP key"): 63 # Note: this needs a tty because of pinentry 64 machine.send_chars("gpg --gen-key\n") 65 machine.wait_until_tty_matches("1", "Real name:") 66 machine.send_chars("Alice\n") 67 machine.wait_until_tty_matches("1", "Email address:") 68 machine.send_chars("alice@machine\n") 69 machine.wait_until_tty_matches("1", "Change") 70 machine.send_chars("O\n") 71 machine.wait_until_tty_matches("1", "Please enter") 72 machine.send_chars("pgp_p4ssphrase\n") 73 machine.wait_until_tty_matches("1", "Please re-enter") 74 machine.send_chars("pgp_p4ssphrase\n") 75 machine.wait_until_tty_matches("1", "public and secret key created") 76 77 with subtest("Confirm the key is in the keyring"): 78 machine.wait_until_succeeds(as_alice("gpg --list-secret-keys | grep -q alice@machine")) 79 80 with subtest("Can generate and add an SSH key"): 81 machine.succeed(as_alice("ssh-keygen -t ed25519 -f alice -N ssh_p4ssphrase")) 82 83 # Note: apparently this must be run before using the OpenSSH agent 84 # socket for the first time in a tty. It's not needed for `ssh` 85 # because there's a hook that calls it automatically (only in NixOS). 86 machine.send_chars("gpg-connect-agent updatestartuptty /bye\n") 87 88 # Note: again, this needs a tty because of pinentry 89 machine.send_chars("ssh-add alice\n") 90 machine.wait_until_tty_matches("1", "Enter passphrase") 91 machine.send_chars("ssh_p4ssphrase\n") 92 machine.wait_until_tty_matches("1", "Please enter") 93 machine.send_chars("ssh_agent_p4ssphrase\n") 94 machine.wait_until_tty_matches("1", "Please re-enter") 95 machine.send_chars("ssh_agent_p4ssphrase\n") 96 97 with subtest("Confirm the SSH key has been registered"): 98 machine.wait_until_succeeds(as_alice("ssh-add -l | grep -q alice@machine")) 99 100 with subtest("Can preset the key passphrases in the agent"): 101 machine.succeed(as_alice("echo allow-preset-passphrase > .gnupg/gpg-agent.conf")) 102 machine.succeed(as_alice("pkill gpg-agent")) 103 machine.succeed(as_alice("preset_key pgp pgp_p4ssphrase")) 104 machine.succeed(as_alice("preset_key ssh ssh_agent_p4ssphrase")) 105 106 with subtest("Can encrypt and decrypt a message"): 107 machine.succeed(as_alice("echo Hello | gpg -e -r alice | gpg -d | grep -q Hello")) 108 109 with subtest("Can log into the server"): 110 # Install Alice's public key 111 public_key = machine.succeed(as_alice("cat alice.pub")) 112 server.succeed("mkdir /etc/ssh/authorized_keys.d") 113 server.succeed(f"printf '{public_key}' > /etc/ssh/authorized_keys.d/alice") 114 115 server.wait_for_open_port(22) 116 machine.succeed(as_alice("ssh -i alice -o StrictHostKeyChecking=no server exit")) 117 ''; 118})