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