, expire ? "-"
, passPath
, subKeys ? {}
+ , postRun ? ""
, ...
}@primary:
''
info "generateKey uid=\"${uid}\""
if ! ${gpg-with-home}/bin/gpg-with-home --list-secret-keys -- "=${uid}" >/dev/null 2>/dev/null
then
- ${pkgs.pass}/bin/pass "${passPath}" |
+ ${if passPath != "" then "${pkgs.pass}/bin/pass '${passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--batch --pinentry-mode loopback --passphrase-fd 0 \
--quick-generate-key "${uid}" "${algo}" "${unwords usage}" "${expire}"
${head1}
fpr=$(${gpg-fingerprint}/bin/gpg-fingerprint -- "=${uid}" | head1)
caps=$(${gpg-with-home}/bin/gpg-with-home \
- --with-colons --fixed-list-mode --with-fingerprint \
+ --with-colons --with-fingerprint \
--list-secret-keys -- "=${uid}" |
${pkgs.gnugrep}/bin/grep '^ssb:' |
${pkgs.coreutils}/bin/cut -d : -f 12 || true)
''
+ unlines (map (generateSubKey primary) subKeys)
+ generateBackupKey "$fpr" primary
+ + postRun
;
generateSubKey =
primary:
info " generateSubKey usage=[${unwords usage}]"
if ! printf '%s\n' "$caps" | ${pkgs.gnugrep}/bin/grep -Fqx "${lettersKeyUsage usage}"
then
- ${pkgs.pass}/bin/pass "${primary.passPath}" |
+ ${if primary.passPath != "" then "${pkgs.pass}/bin/pass '${primary.passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--batch --pinentry-mode loopback --passphrase-fd 0 \
--quick-add-key "$fpr" "${algo}" "${unwords usage}" "${expire}"
fi
'' + (if backupRecipients == [""] then
''
- if ! test -s "${gnupg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc"
+ if ! test -s "${gnupg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc" &&
+ ${gpg-with-home}/bin/gpg-with-home --list-secret-keys "${fpr}" | grep -q "sec "
then
- ${pkgs.pass}/bin/pass "${passPath}" |
+ ${if passPath != "" then "${pkgs.pass}/bin/pass '${passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--pinentry-mode loopback --passphrase-fd 0 \
--armor --yes --output "${gnupg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc" \
fi
if ! test -s "${gnupg.gnupgHome}/backup/${uid}/${fpr}.privkey.sec"
then
- ${pkgs.pass}/bin/pass "${passPath}" |
+ ${if passPath != "" then "${pkgs.pass}/bin/pass '${passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--batch --pinentry-mode loopback --passphrase-fd 0 \
--armor --yes --output "${gnupg.gnupgHome}/backup/${uid}/${fpr}.privkey.sec" \
fi
if ! test -s "${gnupg.gnupgHome}/backup/${uid}/${fpr}.subkeys.sec"
then
- ${pkgs.pass}/bin/pass "${passPath}" |
+ ${if passPath != "" then "${pkgs.pass}/bin/pass '${passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--batch --pinentry-mode loopback --passphrase-fd 0 \
--armor --yes --output "${gnupg.gnupgHome}/backup/${uid}/${fpr}.subkeys.sec" \
'' else ''
if ! test -s "${gnupg.gnupgHome}/backup/${uid}/${fpr}.revoke.asc.gpg"
then
- ${pkgs.pass}/bin/pass "${passPath}" |
+ ${if passPath != "" then "${pkgs.pass}/bin/pass '${passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--pinentry-mode loopback --passphrase-fd 0 \
--armor --gen-revoke "${fpr}" |
fi
if ! test -s "${gnupg.gnupgHome}/backup/${uid}/${fpr}.privkey.sec.gpg"
then
- ${pkgs.pass}/bin/pass "${passPath}" |
+ ${if passPath != "" then "${pkgs.pass}/bin/pass '${passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--batch --pinentry-mode loopback --passphrase-fd 0 \
--armor --export-options export-backup \
fi
if ! test -s "${gnupg.gnupgHome}/backup/${uid}/${fpr}.subkeys.sec.gpg"
then
- ${pkgs.pass}/bin/pass "${passPath}" |
+ ${if passPath != "" then "${pkgs.pass}/bin/pass '${passPath}'" else "cat /dev/null"} |
${gpg-with-home}/bin/gpg-with-home \
--batch --pinentry-mode loopback --passphrase-fd 0 \
--armor --export-options export-backup \
gpg-fingerprint = pkgs.writeScriptBin "gpg-fingerprint" ''
set -eu
${gpg-with-home}/bin/gpg-with-home \
- --with-colons --fixed-list-mode --with-fingerprint --with-subkey-fingerprint \
+ --with-colons --with-fingerprint --with-subkey-fingerprint \
--list-public-keys "$@" |
while IFS=: read -r t x x x key x x x x uid x
do case $t in
gpg-keygrip = pkgs.writeScriptBin "gpg-keygrip" ''
set -eu
${gpg-with-home}/bin/gpg-with-home \
- --with-colons --fixed-list-mode --with-keygrip \
+ --with-colons --with-keygrip \
--list-public-keys "$@" |
- while IFS=: read -r t x x x key x x x x uid x
- do case $t in
- (pub|sub|sec|ssb)
- while IFS=: read -r t x x x x x x x x grp x
- do case $t in (grp) printf '%s\n' "$grp"; break;;
- esac done
- ;;
- esac done
+ while IFS=: read -r t x x x key x x x x uid x do case $t in (pub|sub|sec|ssb) while IFS=: read -r t x x x x x x x x grp x do case $t in (grp) printf '%s\n' "$grp"; break;; esac done ;; esac done
'';
# A wrapper around gpg to get uids.
gpg-uid = pkgs.writeScriptBin "gpg-uid" ''
set -eu
${gpg-with-home}/bin/gpg-with-home \
- --with-colons --fixed-list-mode \
+ --with-colons \
--list-public-keys "$@" |
while IFS=: read -r t st x x x x x id x uid x
do case $t in
options.gnupg = {
enable = lib.mkEnableOption "GnuPG shell utilities";
gnupgHome = lib.mkOption {
- type = types.path;
+ type = types.str;
default = "sec/gnupg";
description = ''
'';
backupRecipients = ["@john@doe.pro"];
};
};
- type = types.attrsOf (types.submodule ({uid, ...}: {
- #config.uid = lib.mkDefault uid;
+ type = types.attrsOf (types.submodule ({name, ...}: {
options = {
uid = lib.mkOption {
type = types.str;
example = "John Doe <john.doe@example.coop>";
- default = uid;
+ default = name;
description = ''
User ID.
'';
};
expire = lib.mkOption {
type = types.str;
- default = "1y";
+ default = "0";
example = "1y";
description = ''
Expiration timeout.
};
expire = lib.mkOption {
type = types.str;
- default = "1y";
+ default = "0";
example = "1y";
description = ''
Expiration timeout.
Backup keys used to encrypt the a backup copy of the secret keys.
'';
};
+ postRun = lib.mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ Shell code to run after the key has been generated or tested to exist.
+ '';
+ };
};
}));
};
allow-ocsp
hkp-cacert ${gnupg.keyserverPEM}
keyserver hkps://keys.mayfirst.org
- use-tor
+ #use-tor
#log-file ${gnupg.gnupgHome}/dirmngr.log
#standard-resolver
'';
};
gpgAgentConf = lib.mkOption {
type = types.lines;
- apply = s: pkgs.writeText "gpg-agent.conf" s;
- default = ''
+ apply = s: pkgs.writeText "gpg-agent.conf" (s+"\n"+gnupg.gpgAgentExtraConf);
+ default =
+ let pinentry = pkgs.writeShellScript "pinentry" ''
+ #!${pkgs.runtimeShell}
+ # choose pinentry depending on PINENTRY_USER_DATA
+ # this *only works* with gpg2
+ # see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=802020
+ case "''${PINENTRY_USER_DATA:-curses}" in
+ curses) exec ${pkgs.pinentry.curses}/bin/pinentry-curses "$@";;
+ #emacs) exec ''${pkgs.pinentry.emacs}/bin/pinentry-emacs "$@";;
+ #gnome3) exec ''${pkgs.pinentry.gnome3}/bin/pinentry-gnome3 "$@";;
+ gtk-2) exec ${pkgs.pinentry.gtk2}/bin/pinentry-gtk-2 "$@";;
+ none) exit 1;; # do not ask for passphrase
+ #qt) exec ''${pkgs.pinentry.qt}/bin/pinentry-qt "$@";;
+ tty) exec ${pkgs.pinentry.tty}/bin/pinentry-tty "$@";;
+ esac
+ '';
+ in ''
+ allow-loopback-pinentry
allow-preset-passphrase
default-cache-ttl 17200
default-cache-ttl-ssh 17200
enable-ssh-support
max-cache-ttl 17200
max-cache-ttl-ssh 17200
- pinentry-program ${pkgs.pinentry}/bin/pinentry
+ no-allow-external-cache
+ pinentry-program ${pinentry}
'';
description = ''
GnuPG's gpg-agent.conf content.
cert-digest-algo SHA512
charset utf-8
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 TWOFISH BZIP2 ZLIB ZIP Uncompressed
- fixed-list-mode
keyid-format 0xlong
keyserver-options no-honor-keyserver-url
no-auto-key-locate
GnuPG's gpg.conf extra content.
'';
};
+ gpgAgentExtraConf = lib.mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ GnuPG's gpg-agent.conf extra content.
+ '';
+ };
};
config = lib.mkIf gnupg.enable {
nix-shell.buildInputs = [