2021-12-05 19:40:24 +00:00
|
|
|
{ config, lib, options, pkgs, ... }:
|
2017-02-10 17:36:36 +00:00
|
|
|
|
|
|
|
let
|
2021-12-05 19:40:24 +00:00
|
|
|
inherit (lib) literalExpression mkOption types;
|
2017-02-10 17:36:36 +00:00
|
|
|
cfg = config.security.dhparams;
|
2021-12-05 19:40:24 +00:00
|
|
|
opt = options.security.dhparams;
|
2018-04-26 04:19:48 +00:00
|
|
|
|
2018-05-07 02:33:56 +00:00
|
|
|
bitType = types.addCheck types.int (b: b >= 16) // {
|
|
|
|
name = "bits";
|
|
|
|
description = "integer of at least 16 bits";
|
|
|
|
};
|
|
|
|
|
2018-04-26 04:19:48 +00:00
|
|
|
paramsSubmodule = { name, config, ... }: {
|
|
|
|
options.bits = mkOption {
|
2018-05-07 02:33:56 +00:00
|
|
|
type = bitType;
|
|
|
|
default = cfg.defaultBitSize;
|
2021-12-05 19:40:24 +00:00
|
|
|
defaultText = literalExpression "config.${opt.defaultBitSize}";
|
2018-04-26 04:19:48 +00:00
|
|
|
description = lib.mdDoc ''
|
|
|
|
The bit size for the prime that is used during a Diffie-Hellman
|
|
|
|
key exchange.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
options.path = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
readOnly = true;
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
The resulting path of the generated Diffie-Hellman parameters
|
|
|
|
file for other services to reference. This could be either a
|
|
|
|
store path or a file inside the directory specified by
|
|
|
|
{option}`security.dhparams.path`.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-04-26 04:38:02 +00:00
|
|
|
config.path = let
|
|
|
|
generated = pkgs.runCommand "dhparams-${name}.pem" {
|
|
|
|
nativeBuildInputs = [ pkgs.openssl ];
|
|
|
|
} "openssl dhparam -out \"$out\" ${toString config.bits}";
|
|
|
|
in if cfg.stateful then "${cfg.path}/${name}.pem" else generated;
|
2018-04-26 04:19:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
in {
|
2017-02-10 17:36:36 +00:00
|
|
|
options = {
|
|
|
|
security.dhparams = {
|
2018-04-26 05:11:54 +00:00
|
|
|
enable = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = false;
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
Whether to generate new DH params and clean up old DH params.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2017-02-10 17:36:36 +00:00
|
|
|
params = mkOption {
|
2018-04-26 04:19:48 +00:00
|
|
|
type = with types; let
|
|
|
|
coerce = bits: { inherit bits; };
|
2018-04-26 05:11:54 +00:00
|
|
|
in attrsOf (coercedTo int coerce (submodule paramsSubmodule));
|
2017-02-10 17:36:36 +00:00
|
|
|
default = {};
|
2021-10-03 16:06:03 +00:00
|
|
|
example = lib.literalExpression "{ nginx.bits = 3072; }";
|
2018-04-26 05:11:54 +00:00
|
|
|
description = lib.mdDoc ''
|
|
|
|
Diffie-Hellman parameters to generate.
|
|
|
|
|
|
|
|
The value is the size (in bits) of the DH params to generate. The
|
|
|
|
generated DH params path can be found in
|
2022-08-02 23:57:59 +00:00
|
|
|
`config.security.dhparams.params.«name».path`.
|
2018-04-26 05:11:54 +00:00
|
|
|
|
|
|
|
::: {.note}
|
|
|
|
The name of the DH params is taken as being the name of
|
|
|
|
the service it serves and the params will be generated before the
|
|
|
|
said service is started.
|
2022-08-30 00:30:04 +00:00
|
|
|
:::
|
2018-04-26 05:11:54 +00:00
|
|
|
|
|
|
|
::: {.warning}
|
|
|
|
If you are removing all dhparams from this list, you
|
|
|
|
have to leave {option}`security.dhparams.enable` for at
|
|
|
|
least one activation in order to have them be cleaned up. This also
|
|
|
|
means if you rollback to a version without any dhparams the
|
|
|
|
existing ones won't be cleaned up. Of course this only applies if
|
|
|
|
{option}`security.dhparams.stateful` is
|
|
|
|
`true`.
|
2022-08-30 00:30:04 +00:00
|
|
|
:::
|
2018-05-07 02:33:56 +00:00
|
|
|
|
|
|
|
::: {.note}
|
|
|
|
**For module implementers:** It's recommended
|
|
|
|
to not set a specific bit size here, so that users can easily
|
|
|
|
override this by setting
|
|
|
|
{option}`security.dhparams.defaultBitSize`.
|
2022-08-30 00:30:04 +00:00
|
|
|
:::
|
2018-04-26 05:11:54 +00:00
|
|
|
'';
|
2017-02-10 17:36:36 +00:00
|
|
|
};
|
|
|
|
|
2018-04-26 04:38:02 +00:00
|
|
|
stateful = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
Whether generation of Diffie-Hellman parameters should be stateful or
|
|
|
|
not. If this is enabled, PEM-encoded files for Diffie-Hellman
|
|
|
|
parameters are placed in the directory specified by
|
|
|
|
{option}`security.dhparams.path`. Otherwise the files are
|
|
|
|
created within the Nix store.
|
|
|
|
|
|
|
|
::: {.note}
|
|
|
|
If this is `false` the resulting store
|
|
|
|
path will be non-deterministic and will be rebuilt every time the
|
2022-08-13 03:15:06 +00:00
|
|
|
`openssl` package changes.
|
2022-08-30 00:30:04 +00:00
|
|
|
:::
|
2018-04-26 04:38:02 +00:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-05-07 02:33:56 +00:00
|
|
|
defaultBitSize = mkOption {
|
|
|
|
type = bitType;
|
|
|
|
default = 2048;
|
|
|
|
description = lib.mdDoc ''
|
|
|
|
This allows to override the default bit size for all of the
|
|
|
|
Diffie-Hellman parameters set in
|
|
|
|
{option}`security.dhparams.params`.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2017-02-10 17:36:36 +00:00
|
|
|
path = mkOption {
|
2018-04-26 05:11:54 +00:00
|
|
|
type = types.str;
|
|
|
|
default = "/var/lib/dhparams";
|
2018-04-26 04:38:02 +00:00
|
|
|
description = lib.mdDoc ''
|
|
|
|
Path to the directory in which Diffie-Hellman parameters will be
|
|
|
|
stored. This only is relevant if
|
|
|
|
{option}`security.dhparams.stateful` is
|
|
|
|
`true`.
|
|
|
|
'';
|
2017-03-17 00:56:13 +00:00
|
|
|
};
|
2017-02-10 17:36:36 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-04-26 05:11:54 +00:00
|
|
|
config = lib.mkIf (cfg.enable && cfg.stateful) {
|
2017-03-17 00:56:13 +00:00
|
|
|
systemd.services = {
|
|
|
|
dhparams-init = {
|
2018-04-26 05:11:54 +00:00
|
|
|
description = "Clean Up Old Diffie-Hellman Parameters";
|
|
|
|
|
|
|
|
# Clean up even when no DH params is set
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
|
|
|
serviceConfig.RemainAfterExit = true;
|
2017-03-17 00:56:13 +00:00
|
|
|
serviceConfig.Type = "oneshot";
|
2018-04-26 05:11:54 +00:00
|
|
|
|
|
|
|
script = ''
|
|
|
|
if [ ! -d ${cfg.path} ]; then
|
|
|
|
mkdir -p ${cfg.path}
|
|
|
|
fi
|
|
|
|
|
2017-03-17 00:56:13 +00:00
|
|
|
# Remove old dhparams
|
2018-04-26 05:11:54 +00:00
|
|
|
for file in ${cfg.path}/*; do
|
|
|
|
if [ ! -f "$file" ]; then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
${lib.concatStrings (lib.mapAttrsToList (name: { bits, path, ... }: ''
|
|
|
|
if [ "$file" = ${lib.escapeShellArg path} ] && \
|
|
|
|
${pkgs.openssl}/bin/openssl dhparam -in "$file" -text \
|
|
|
|
| head -n 1 | grep "(${toString bits} bit)" > /dev/null; then
|
2017-03-17 00:56:13 +00:00
|
|
|
continue
|
|
|
|
fi
|
2018-04-26 05:11:54 +00:00
|
|
|
'') cfg.params)}
|
|
|
|
rm $file
|
|
|
|
done
|
|
|
|
|
|
|
|
# TODO: Ideally this would be removing the *former* cfg.path, though
|
|
|
|
# this does not seem really important as changes to it are quite
|
|
|
|
# unlikely
|
|
|
|
rmdir --ignore-fail-on-non-empty ${cfg.path}
|
|
|
|
'';
|
2017-03-17 00:56:13 +00:00
|
|
|
};
|
2018-04-26 05:11:54 +00:00
|
|
|
} // lib.mapAttrs' (name: { bits, path, ... }: lib.nameValuePair "dhparams-gen-${name}" {
|
|
|
|
description = "Generate Diffie-Hellman Parameters for ${name}";
|
|
|
|
after = [ "dhparams-init.service" ];
|
|
|
|
before = [ "${name}.service" ];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
unitConfig.ConditionPathExists = "!${path}";
|
|
|
|
serviceConfig.Type = "oneshot";
|
|
|
|
script = ''
|
|
|
|
mkdir -p ${lib.escapeShellArg cfg.path}
|
|
|
|
${pkgs.openssl}/bin/openssl dhparam -out ${lib.escapeShellArg path} \
|
|
|
|
${toString bits}
|
|
|
|
'';
|
|
|
|
}) cfg.params;
|
2017-03-17 00:56:13 +00:00
|
|
|
};
|
2018-10-30 16:05:35 +00:00
|
|
|
|
|
|
|
meta.maintainers = with lib.maintainers; [ ekleog ];
|
2017-02-10 17:36:36 +00:00
|
|
|
}
|