diff options
Diffstat (limited to 'modules/programs/gnupg/default.nix')
-rw-r--r-- | modules/programs/gnupg/default.nix | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/modules/programs/gnupg/default.nix b/modules/programs/gnupg/default.nix new file mode 100644 index 00000000..c6034f11 --- /dev/null +++ b/modules/programs/gnupg/default.nix @@ -0,0 +1,174 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.vuizvui.programs.gnupg; + + pinentryWrapper = pkgs.runCommand "pinentry-wrapper" { + pinentryProgram = cfg.agent.pinentry.program; + } '' + cc -Wall -std=gnu11 -DPINENTRY_PROGRAM=\"$pinentryProgram\" \ + "${./pinentry-wrapper.c}" -o "$out" + ''; + + scdaemonRedirector = pkgs.writeScript "scdaemon-redirector" '' + #!${pkgs.stdenv.shell} + exec "${pkgs.socat}/bin/socat" - \ + UNIX-CONNECT:"$HOME/${cfg.homeDir}/S.scdaemon" + ''; + + agentWrapper = pkgs.runCommand "gpg-agent-wrapper" { + buildInputs = with pkgs; [ pkgconfig systemd ]; + inherit pinentryWrapper; + } '' + cc -Wall -shared -std=c11 \ + -DLIBSYSTEMD=\"${pkgs.systemd}/lib/libsystemd.so\" \ + -DPINENTRY_WRAPPER=\"$pinentryWrapper\" \ + $(pkg-config --cflags libsystemd) -ldl \ + "${./agent-wrapper.c}" -o "$out" -fPIC + ''; + + agentSocketConfig = name: { + FileDescriptorName = name; + Service = "gpg-agent.service"; + SocketMode = "0600"; + DirectoryMode = "0700"; + }; + +in { + options.vuizvui.programs.gnupg = { + enable = mkEnableOption "support for GnuPG"; + + homeDir = mkOption { + type = types.addCheck types.str (d: builtins.substring 0 1 d != "/"); + default = ".gnupg"; + description = '' + The directory where GnuPG keeps its state files and configuration files, + relative to the user's home directory. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.gnupg; + defaultText = "pkgs.gnupg"; + example = literalExample "pkgs.gnupg21"; + description = '' + The GnuPG package to use for running the agent and make available in + <option>environment.systemPackages</option>. + ''; + }; + + agent = { + enable = mkEnableOption "support for the GnuPG agent"; + + pinentry.program = mkOption { + type = types.path; + default = "${pkgs.pinentry}/bin/pinentry"; + defaultText = "\${pkgs.pinentry}/bin/pinentry"; + example = literalExample "\${pkgs.pinentry_qt5}/bin/pinentry"; + description = "The pinentry program to use to ask for passphrases."; + }; + + sshSupport = mkEnableOption "GnuPG agent support for SSH"; + + scdaemon = { + enable = mkEnableOption "GnuPG agent with Smartcard daemon"; + + program = mkOption { + type = types.path; + default = "${cfg.package}/libexec/scdaemon"; + defaultText = let + configPath = "config.vuizvui.programs.gnupg"; + in "\${${configPath}.package}/libexec/scdaemon"; + example = literalExample "\${pkgs.my_shiny_scdaemon}/bin/scdaemon"; + description = "The program to use for the Smartcard daemon"; + }; + }; + }; + }; + + config = mkMerge [ + (mkIf cfg.enable { + vuizvui.requiresTests = singleton ["vuizvui" "programs" "gnupg"]; + environment.systemPackages = [ cfg.package ]; + environment.variables.GNUPGHOME = "~/${cfg.homeDir}"; + }) + (mkIf (cfg.enable && cfg.agent.enable) { + systemd.user.services.gpg-agent = { + description = "GnuPG Agent"; + environment.LD_PRELOAD = agentWrapper; + environment.GNUPGHOME = "~/${cfg.homeDir}"; + + serviceConfig.ExecStart = toString ([ + "${cfg.package}/bin/gpg-agent" + "--pinentry-program=${pinentryWrapper}" + (if cfg.agent.scdaemon.enable + then "--scdaemon-program=${scdaemonRedirector}" + else "--disable-scdaemon") + "--no-detach" + "--daemon" + ] ++ optional cfg.agent.sshSupport "--enable-ssh-support"); + + serviceConfig.ExecReload = toString [ + "${cfg.package}/bin/gpg-connect-agent" + "RELOADAGENT" + "/bye" + ]; + }; + + systemd.user.sockets.gpg-agent-main = { + wantedBy = [ "sockets.target" ]; + description = "Main Socket For GnuPG Agent"; + listenStreams = [ "%h/${cfg.homeDir}/S.gpg-agent" ]; + socketConfig = agentSocketConfig "main"; + }; + }) + (mkIf (cfg.enable && cfg.agent.enable && cfg.agent.scdaemon.enable) { + systemd.user.sockets.gnupg-scdaemon = { + wantedBy = [ "sockets.target" ]; + description = "GnuPG Smartcard Daemon Socket"; + listenStreams = [ "%h/${cfg.homeDir}/S.scdaemon" ]; + socketConfig = { + FileDescriptorName = "scdaemon"; + SocketMode = "0600"; + DirectoryMode = "0700"; + }; + }; + + systemd.user.services.gnupg-scdaemon = { + description = "GnuPG Smartcard Daemon"; + environment.LD_PRELOAD = agentWrapper; + environment.GNUPGHOME = "~/${cfg.homeDir}"; + + serviceConfig.ExecStart = toString [ + "${cfg.agent.scdaemon.program}" + "--no-detach" + "--daemon" + ]; + }; + }) + (mkIf (cfg.enable && cfg.agent.enable && cfg.agent.sshSupport) { + environment.variables.SSH_AUTH_SOCK = + "$HOME/${cfg.homeDir}/S.gpg-agent.ssh"; + + systemd.user.sockets.gpg-agent-ssh = { + wantedBy = [ "sockets.target" ]; + description = "SSH Socket For GnuPG Agent"; + listenStreams = [ "%h/${cfg.homeDir}/S.gpg-agent.ssh" ]; + socketConfig = agentSocketConfig "ssh"; + }; + + assertions = singleton { + assertion = !config.programs.ssh.startAgent; + message = toString [ + "You cannot use the GnuPG agent with SSH support in addition to the" + "SSH agent, please either disable" + "`vuizvui.programs.gpg-agent.sshSupport' or disable" + "`programs.ssh.startAgent'." + ]; + }; + }) + ]; +} |