at 23.11-beta 7.9 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.programs.gnupg; 8 9 agentSettingsFormat = pkgs.formats.keyValue { 10 mkKeyValue = lib.generators.mkKeyValueDefault { } " "; 11 }; 12 13 xserverCfg = config.services.xserver; 14 15 defaultPinentryFlavor = 16 if xserverCfg.desktopManager.lxqt.enable 17 || xserverCfg.desktopManager.plasma5.enable 18 || xserverCfg.desktopManager.deepin.enable then 19 "qt" 20 else if xserverCfg.desktopManager.xfce.enable then 21 "gtk2" 22 else if xserverCfg.enable || config.programs.sway.enable then 23 "gnome3" 24 else 25 "curses"; 26 27in 28 29{ 30 31 options.programs.gnupg = { 32 package = mkOption { 33 type = types.package; 34 default = pkgs.gnupg; 35 defaultText = literalExpression "pkgs.gnupg"; 36 description = lib.mdDoc '' 37 The gpg package that should be used. 38 ''; 39 }; 40 41 agent.enable = mkOption { 42 type = types.bool; 43 default = false; 44 description = lib.mdDoc '' 45 Enables GnuPG agent with socket-activation for every user session. 46 ''; 47 }; 48 49 agent.enableSSHSupport = mkOption { 50 type = types.bool; 51 default = false; 52 description = lib.mdDoc '' 53 Enable SSH agent support in GnuPG agent. Also sets SSH_AUTH_SOCK 54 environment variable correctly. This will disable socket-activation 55 and thus always start a GnuPG agent per user session. 56 ''; 57 }; 58 59 agent.enableExtraSocket = mkOption { 60 type = types.bool; 61 default = false; 62 description = lib.mdDoc '' 63 Enable extra socket for GnuPG agent. 64 ''; 65 }; 66 67 agent.enableBrowserSocket = mkOption { 68 type = types.bool; 69 default = false; 70 description = lib.mdDoc '' 71 Enable browser socket for GnuPG agent. 72 ''; 73 }; 74 75 agent.pinentryFlavor = mkOption { 76 type = types.nullOr (types.enum pkgs.pinentry.flavors); 77 example = "gnome3"; 78 default = defaultPinentryFlavor; 79 defaultText = literalMD ''matching the configured desktop environment''; 80 description = lib.mdDoc '' 81 Which pinentry interface to use. If not null, the path to the 82 pinentry binary will be set in /etc/gnupg/gpg-agent.conf. 83 If not set at all, it'll pick an appropriate flavor depending on the 84 system configuration (qt flavor for lxqt and plasma5, gtk2 for xfce 85 4.12, gnome3 on all other systems with X enabled, ncurses otherwise). 86 ''; 87 }; 88 89 agent.settings = mkOption { 90 type = agentSettingsFormat.type; 91 default = { }; 92 example = { 93 default-cache-ttl = 600; 94 }; 95 description = lib.mdDoc '' 96 Configuration for /etc/gnupg/gpg-agent.conf. 97 See {manpage}`gpg-agent(1)` for supported options. 98 ''; 99 }; 100 101 dirmngr.enable = mkOption { 102 type = types.bool; 103 default = false; 104 description = lib.mdDoc '' 105 Enables GnuPG network certificate management daemon with socket-activation for every user session. 106 ''; 107 }; 108 }; 109 110 config = mkIf cfg.agent.enable { 111 programs.gnupg.agent.settings = { 112 pinentry-program = lib.mkIf (cfg.agent.pinentryFlavor != null) 113 "${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry"; 114 }; 115 116 environment.etc."gnupg/gpg-agent.conf".source = 117 agentSettingsFormat.generate "gpg-agent.conf" cfg.agent.settings; 118 119 # This overrides the systemd user unit shipped with the gnupg package 120 systemd.user.services.gpg-agent = { 121 unitConfig = { 122 Description = "GnuPG cryptographic agent and passphrase cache"; 123 Documentation = "man:gpg-agent(1)"; 124 Requires = [ "sockets.target" ]; 125 }; 126 serviceConfig = { 127 ExecStart = "${cfg.package}/bin/gpg-agent --supervised"; 128 ExecReload = "${cfg.package}/bin/gpgconf --reload gpg-agent"; 129 }; 130 }; 131 132 systemd.user.sockets.gpg-agent = { 133 unitConfig = { 134 Description = "GnuPG cryptographic agent and passphrase cache"; 135 Documentation = "man:gpg-agent(1)"; 136 }; 137 socketConfig = { 138 ListenStream = "%t/gnupg/S.gpg-agent"; 139 FileDescriptorName = "std"; 140 SocketMode = "0600"; 141 DirectoryMode = "0700"; 142 }; 143 wantedBy = [ "sockets.target" ]; 144 }; 145 146 systemd.user.sockets.gpg-agent-ssh = mkIf cfg.agent.enableSSHSupport { 147 unitConfig = { 148 Description = "GnuPG cryptographic agent (ssh-agent emulation)"; 149 Documentation = "man:gpg-agent(1) man:ssh-add(1) man:ssh-agent(1) man:ssh(1)"; 150 }; 151 socketConfig = { 152 ListenStream = "%t/gnupg/S.gpg-agent.ssh"; 153 FileDescriptorName = "ssh"; 154 Service = "gpg-agent.service"; 155 SocketMode = "0600"; 156 DirectoryMode = "0700"; 157 }; 158 wantedBy = [ "sockets.target" ]; 159 }; 160 161 systemd.user.sockets.gpg-agent-extra = mkIf cfg.agent.enableExtraSocket { 162 unitConfig = { 163 Description = "GnuPG cryptographic agent and passphrase cache (restricted)"; 164 Documentation = "man:gpg-agent(1)"; 165 }; 166 socketConfig = { 167 ListenStream = "%t/gnupg/S.gpg-agent.extra"; 168 FileDescriptorName = "extra"; 169 Service = "gpg-agent.service"; 170 SocketMode = "0600"; 171 DirectoryMode = "0700"; 172 }; 173 wantedBy = [ "sockets.target" ]; 174 }; 175 176 systemd.user.sockets.gpg-agent-browser = mkIf cfg.agent.enableBrowserSocket { 177 unitConfig = { 178 Description = "GnuPG cryptographic agent and passphrase cache (access for web browsers)"; 179 Documentation = "man:gpg-agent(1)"; 180 }; 181 socketConfig = { 182 ListenStream = "%t/gnupg/S.gpg-agent.browser"; 183 FileDescriptorName = "browser"; 184 Service = "gpg-agent.service"; 185 SocketMode = "0600"; 186 DirectoryMode = "0700"; 187 }; 188 wantedBy = [ "sockets.target" ]; 189 }; 190 191 systemd.user.services.dirmngr = mkIf cfg.dirmngr.enable { 192 unitConfig = { 193 Description = "GnuPG network certificate management daemon"; 194 Documentation = "man:dirmngr(8)"; 195 Requires = "dirmngr.socket"; 196 }; 197 serviceConfig = { 198 ExecStart = "${cfg.package}/bin/dirmngr --supervised"; 199 ExecReload = "${cfg.package}/bin/gpgconf --reload dirmngr"; 200 }; 201 }; 202 203 systemd.user.sockets.dirmngr = mkIf cfg.dirmngr.enable { 204 unitConfig = { 205 Description = "GnuPG network certificate management daemon"; 206 Documentation = "man:dirmngr(8)"; 207 }; 208 socketConfig = { 209 ListenStream = "%t/gnupg/S.dirmngr"; 210 SocketMode = "0600"; 211 DirectoryMode = "0700"; 212 }; 213 wantedBy = [ "sockets.target" ]; 214 }; 215 216 services.dbus.packages = mkIf (cfg.agent.pinentryFlavor == "gnome3") [ pkgs.gcr ]; 217 218 environment.systemPackages = with pkgs; [ cfg.package ]; 219 220 environment.interactiveShellInit = '' 221 # Bind gpg-agent to this TTY if gpg commands are used. 222 export GPG_TTY=$(tty) 223 ''; 224 225 programs.ssh.extraConfig = optionalString cfg.agent.enableSSHSupport '' 226 # The SSH agent protocol doesn't have support for changing TTYs; however we 227 # can simulate this with the `exec` feature of openssh (see ssh_config(5)) 228 # that hooks a command to the shell currently running the ssh program. 229 Match host * exec "${pkgs.runtimeShell} -c '${cfg.package}/bin/gpg-connect-agent --quiet updatestartuptty /bye >/dev/null 2>&1'" 230 ''; 231 232 environment.extraInit = mkIf cfg.agent.enableSSHSupport '' 233 if [ -z "$SSH_AUTH_SOCK" ]; then 234 export SSH_AUTH_SOCK=$(${cfg.package}/bin/gpgconf --list-dirs agent-ssh-socket) 235 fi 236 ''; 237 238 assertions = [ 239 { assertion = cfg.agent.enableSSHSupport -> !config.programs.ssh.startAgent; 240 message = "You can't use ssh-agent and GnuPG agent with SSH support enabled at the same time!"; 241 } 242 ]; 243 }; 244 245 # uses attributes of the linked package 246 meta.buildDocsInSandbox = false; 247}