1 { config, lib, options, pkgs, ... }:
4 inherit (lib) literalExpression mkOption types;
5 cfg = config.security.dhparams;
6 opt = options.security.dhparams;
8 bitType = types.addCheck types.int (b: b >= 16) // {
10 description = "integer of at least 16 bits";
13 paramsSubmodule = { name, config, ... }: {
14 options.bits = mkOption {
16 default = cfg.defaultBitSize;
17 defaultText = literalExpression "config.${opt.defaultBitSize}";
19 The bit size for the prime that is used during a Diffie-Hellman
24 options.path = mkOption {
28 The resulting path of the generated Diffie-Hellman parameters
29 file for other services to reference. This could be either a
30 store path or a file inside the directory specified by
31 {option}`security.dhparams.path`.
36 generated = pkgs.runCommand "dhparams-${name}.pem" {
37 nativeBuildInputs = [ pkgs.openssl ];
38 } "openssl dhparam -out \"$out\" ${toString config.bits}";
39 in if cfg.stateful then "${cfg.path}/${name}.pem" else generated;
49 Whether to generate new DH params and clean up old DH params.
54 type = with types; let
55 coerce = bits: { inherit bits; };
56 in attrsOf (coercedTo int coerce (submodule paramsSubmodule));
58 example = lib.literalExpression "{ nginx.bits = 3072; }";
60 Diffie-Hellman parameters to generate.
62 The value is the size (in bits) of the DH params to generate. The
63 generated DH params path can be found in
64 `config.security.dhparams.params.«name».path`.
67 The name of the DH params is taken as being the name of
68 the service it serves and the params will be generated before the
69 said service is started.
73 If you are removing all dhparams from this list, you
74 have to leave {option}`security.dhparams.enable` for at
75 least one activation in order to have them be cleaned up. This also
76 means if you rollback to a version without any dhparams the
77 existing ones won't be cleaned up. Of course this only applies if
78 {option}`security.dhparams.stateful` is
83 **For module implementers:** It's recommended
84 to not set a specific bit size here, so that users can easily
85 override this by setting
86 {option}`security.dhparams.defaultBitSize`.
95 Whether generation of Diffie-Hellman parameters should be stateful or
96 not. If this is enabled, PEM-encoded files for Diffie-Hellman
97 parameters are placed in the directory specified by
98 {option}`security.dhparams.path`. Otherwise the files are
99 created within the Nix store.
102 If this is `false` the resulting store
103 path will be non-deterministic and will be rebuilt every time the
104 `openssl` package changes.
109 defaultBitSize = mkOption {
113 This allows to override the default bit size for all of the
114 Diffie-Hellman parameters set in
115 {option}`security.dhparams.params`.
121 default = "/var/lib/dhparams";
123 Path to the directory in which Diffie-Hellman parameters will be
124 stored. This only is relevant if
125 {option}`security.dhparams.stateful` is
132 config = lib.mkIf (cfg.enable && cfg.stateful) {
135 description = "Clean Up Old Diffie-Hellman Parameters";
137 # Clean up even when no DH params is set
138 wantedBy = [ "multi-user.target" ];
140 serviceConfig.RemainAfterExit = true;
141 serviceConfig.Type = "oneshot";
144 if [ ! -d ${cfg.path} ]; then
148 # Remove old dhparams
149 for file in ${cfg.path}/*; do
150 if [ ! -f "$file" ]; then
153 ${lib.concatStrings (lib.mapAttrsToList (name: { bits, path, ... }: ''
154 if [ "$file" = ${lib.escapeShellArg path} ] && \
155 ${pkgs.openssl}/bin/openssl dhparam -in "$file" -text \
156 | head -n 1 | grep "(${toString bits} bit)" > /dev/null; then
163 # TODO: Ideally this would be removing the *former* cfg.path, though
164 # this does not seem really important as changes to it are quite
166 rmdir --ignore-fail-on-non-empty ${cfg.path}
169 } // lib.mapAttrs' (name: { bits, path, ... }: lib.nameValuePair "dhparams-gen-${name}" {
170 description = "Generate Diffie-Hellman Parameters for ${name}";
171 after = [ "dhparams-init.service" ];
172 before = [ "${name}.service" ];
173 wantedBy = [ "multi-user.target" ];
174 unitConfig.ConditionPathExists = "!${path}";
175 serviceConfig.Type = "oneshot";
177 mkdir -p ${lib.escapeShellArg cfg.path}
178 ${pkgs.openssl}/bin/openssl dhparam -out ${lib.escapeShellArg path} \
184 meta.maintainers = with lib.maintainers; [ ekleog ];