1{ config, lib, pkgs, ... }:
2
3with lib;
4let
5 cfg = config.security.dhparams;
6in
7{
8 options = {
9 security.dhparams = {
10 params = mkOption {
11 description =
12 ''
13 Diffie-Hellman parameters to generate.
14
15 The value is the size (in bits) of the DH params to generate. The
16 generated DH params path can be found in
17 <filename><replaceable>security.dhparams.path</replaceable>/<replaceable>name</replaceable>.pem</filename>.
18
19 Note: The name of the DH params is taken as being the name of the
20 service it serves: the params will be generated before the said
21 service is started.
22
23 Warning: If you are removing all dhparams from this list, you have
24 to leave security.dhparams.enable for at least one activation in
25 order to have them be cleaned up. This also means if you rollback to
26 a version without any dhparams the existing ones won't be cleaned
27 up.
28 '';
29 type = with types; attrsOf int;
30 default = {};
31 example = { nginx = 3072; };
32 };
33
34 path = mkOption {
35 description =
36 ''
37 Path to the directory in which Diffie-Hellman parameters will be
38 stored.
39 '';
40 type = types.str;
41 default = "/var/lib/dhparams";
42 };
43
44 enable = mkOption {
45 description =
46 ''
47 Whether to generate new DH params and clean up old DH params.
48 '';
49 default = false;
50 type = types.bool;
51 };
52 };
53 };
54
55 config = mkIf cfg.enable {
56 systemd.services = {
57 dhparams-init = {
58 description = "Cleanup old Diffie-Hellman parameters";
59 wantedBy = [ "multi-user.target" ]; # Clean up even when no DH params is set
60 serviceConfig.Type = "oneshot";
61 script =
62 # Create directory
63 ''
64 if [ ! -d ${cfg.path} ]; then
65 mkdir -p ${cfg.path}
66 fi
67 '' +
68 # Remove old dhparams
69 ''
70 for file in ${cfg.path}/*; do
71 if [ ! -f "$file" ]; then
72 continue
73 fi
74 '' + concatStrings (mapAttrsToList (name: value:
75 ''
76 if [ "$file" == "${cfg.path}/${name}.pem" ] && \
77 ${pkgs.openssl}/bin/openssl dhparam -in "$file" -text | head -n 1 | grep "(${toString value} bit)" > /dev/null; then
78 continue
79 fi
80 ''
81 ) cfg.params) +
82 ''
83 rm $file
84 done
85
86 # TODO: Ideally this would be removing the *former* cfg.path, though this
87 # does not seem really important as changes to it are quite unlikely
88 rmdir --ignore-fail-on-non-empty ${cfg.path}
89 '';
90 };
91 } //
92 mapAttrs' (name: value: nameValuePair "dhparams-gen-${name}" {
93 description = "Generate Diffie-Hellman parameters for ${name} if they don't exist yet";
94 after = [ "dhparams-init.service" ];
95 before = [ "${name}.service" ];
96 wantedBy = [ "multi-user.target" ];
97 serviceConfig.Type = "oneshot";
98 script =
99 ''
100 mkdir -p ${cfg.path}
101 if [ ! -f ${cfg.path}/${name}.pem ]; then
102 ${pkgs.openssl}/bin/openssl dhparam -out ${cfg.path}/${name}.pem ${toString value}
103 fi
104 '';
105 }) cfg.params;
106 };
107}