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