{ config, pkgs, lib, ... }: { # Use NitroKey USB smartcard with SSH. # https://nixos.wiki/wiki/Nitrokey # Test suite. TODO: Check all of this after config changes! # - pinentry should be in $PATH # echo GETPIN | pinentry # - smartcard should be listed # gpg --card-status # - encryption should work (graphical pinentry should pop-up) # gpg -d ./passphrase.txt.gpg # - ssh should work (graphical pinentry should pop-up) # ssh yodaNas # - signed git commits should work in IntelliJ # IntelliJ IDE -> git commit -> graphical pinentry should pop-up # Restart gpg-agent after config change. # Otherwise there might be a gpg error about "no pinentry". # https://discourse.nixos.org/t/cant-get-gnupg-to-work-no-pinentry/15373/19 # # But how to restart it? # https://superuser.com/a/1150399 # gpgconf --kill gpg-agent # killall gpg-agent # systemctl --user restart gpg-agent # Not sure if this is needed: Reload udev rules. # sudo -- udevadm control --reload-rules && udevadm trigger # TODO: gpg-agent pinentry problem # https://github.com/NixOS/nixpkgs/issues/97861 # # gpgconf --check-programs #=> gpgconf: error running '/nix/store/lvsbmqy4dmlri22145hbr6799hgbnpnf-gnupg-2.4.0/bin/pinentry': probably not installed # # ssh -v nas #=> OpenSSH_9.3p2, OpenSSL 3.0.10 1 Aug 2023 #=> debug1: Reading configuration data /home/yoda/.ssh/config #=> debug1: /home/yoda/.ssh/config line 67: Applying options for nas #=> debug1: /home/yoda/.ssh/config line 180: Applying options for * #=> debug1: Reading configuration data /etc/ssh/ssh_config #=> debug1: Executing command: '/nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15/bin/bash -c '/nix/store/lvsbmqy4dmlri22145hbr6799hgbnpnf-gnupg-2.4.0/bin/gpg-connect-agent --quiet updatestartuptty /bye >/dev/null 2>&1'' # #=> USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND #=> yoda 2752 0.0 0.0 444812 3040 ? SLsl 16:09 0:00 /nix/store/lvsbmqy4dmlri22145hbr6799hgbnpnf-gnupg-2.4.0/bin/gpg-agent --supervised --pinentry-program /nix/store/8cvidvpwnwyxixlhqfaa5jlfndh2vir5-pinentry-1.2.1-curses/bin/pinentry # NITROKEY SSH WORKAROUND (I): Do all of this in one shell! # CREDITS: https://unix.stackexchange.com/a/250045/315162 # # BEFORE: SSH_AUTH_SOCK=/run/user/1000/keyring/ssh # AFTER: SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh # # systemctl --user stop gpg-agent # systemctl --user stop gpg-agent.socket # systemctl --user stop gpg-agent-ssh.socket # ps -aux | grep -v grep | grep gpg-agent # => NONE # eval $(gpg-agent --daemon --pinentry-program /nix/store/5j87jnmfh19xlq9ij0v3rh7cwssr4586-pinentry-1.2.1-curses/bin/pinentry --enable-ssh-support --sh) # echo $SSH_AUTH_SOCK #=> /run/user/1000/gnupg/S.gpg-agent.ssh # gpg -d ./passphrase.txt.gpg #=> Works! # ssh nas #=> Works! # NITROKEY SSH WORKAROUND (II) # # export SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh # ssh nas #=> Works! # TODO: # What is the difference between programs.gnupg.agent.enableSSHSupport and # services.gpg-agent.enableSshSupport = true; services.udev.packages = [ pkgs.nitrokey-udev-rules ]; programs = { ssh.startAgent = false; gnupg.agent = { enable = true; # Sets SSH_AUTH_SOCK environment variable. enableSSHSupport = true; #pinentryFlavor = "curses"; pinentryFlavor = "gnome3"; }; }; # GNOME Keyring: Disable SSH agent. # # Without this, # export SSH_AUTH_SOCK=/run/user/1000/gnupg/S.gpg-agent.ssh # is required before ssh can use the smartcard (through gpg-agent). # # GNOME Keyring will override the SSH_AUTH_SOCK variable # if it starts its own SSH agent. The docs suggest to disable # SSH agent support in GNOME Keyring if using another SSH agent: # https://wiki.gnome.org/Projects/GnomeKeyring/Ssh # # Here are related issues: # https://github.com/NixOS/nixpkgs/issues/8356 # https://github.com/NixOS/nixpkgs/issues/42291 # https://wiki.archlinux.org/title/GnuPG#GNOME_on_Wayland_overrides_SSH_agent_socket # # Solution 1: https://github.com/NixOS/nixpkgs/issues/42291#issuecomment-399630199 # Works for me. # Solution 2: https://github.com/NixOS/nixpkgs/issues/42291#issuecomment-687979733 # Works for me, but on each login, nextcloud-desktop asks for credentials ... # Adds the pinentry binary to the PATH so that e.g. # echo GETPIN | pinentry # works. # This is not required for # - gpg --card-status # - ssh nas # - signed git commits in IntelliJ #environment.systemPackages = with pkgs; [ # #pinentry-curses # pinentry-gnome #]; #users.users.yoda = { # packages = with pkgs; [ # #pinentry-curses # pinentry-gnome # ]; #}; # https://docs.nitrokey.com/nitrokey3/windows/troubleshooting.html#gnupg-openpgp-card-not-available # # There are two common smartcard services on Linux systems # - scdaemon (gpg) with two drivers: # - ccid: directly accesses smartcard # - pcsc: uses the pcscd daemon to access smartcard # - pcscd (generic smartcard daemon) # # `pcscd` might lock the card before `scdaemon` tries to access it # using the internal `ccid` driver # # Either uninstall `pcscd` **or** # use the `pcscd` driver for `scdaemon` # by adding `disable-ccid` to `~/.gnupg/scdaemon.conf` # Smartcard daemon. services.pcscd.enable = true; home-manager.users.yoda = { osConfig, config, pkgs, ... }: { # Disable GNOME Keyring. See comment above. # # Prevent clobbering SSH_AUTH_SOCK home.sessionVariables.GSM_SKIP_SSH_AGENT_WORKAROUND = "1"; # Disable gnome-keyring ssh-agent xdg.configFile."autostart/gnome-keyring-ssh.desktop".text = '' ${lib.fileContents "${pkgs.gnome3.gnome-keyring}/etc/xdg/autostart/gnome-keyring-ssh.desktop"} Hidden=true ''; # GnuPG configuration. programs.gpg = { enable = true; scdaemonSettings = { disable-ccid = true; }; publicKeys = [{ source = "${../assets/gpg/pubkey_nitrokey.asc}"; # ultimate trust = 5; }]; # Examples: # https://github.com/ioerror/duraconf # https://gist.github.com/graffen/37eaa2332ee7e584bfda settings = { # Display long key IDs keyid-format = "0xlong"; # List all keys (or the specified ones) along with their fingerprints with-fingerprint = true; # Display the calculated validity of user IDs during key listings. list-options = "show-uid-validity"; verify-options = "show-uid-validity"; }; }; }; }