main
1{den, ...}: {
2 den.aspects.desktop.includes = [den.aspects.desktop.gnupg];
3 den.aspects.desktop.gnupg = {
4 nixos = {pkgs, ...}: {
5 programs.gnupg.agent = {
6 enable = true;
7 pinentryPackage = pkgs.pinentry-gnome3;
8 enableSSHSupport = false;
9 settings.default-cache-ttl = 4 * 60 * 60; # 4 hours
10 };
11 };
12
13 provides.to-users = {
14 includes = [
15 {
16 persistHome = {config, ...}: {
17 directories = [
18 {
19 directory = config.environment.sessionVariables.GNUPGHOME;
20 mode = "0700";
21 }
22 ];
23 };
24 }
25 ];
26
27 hjem = {
28 user,
29 pkgs,
30 lib,
31 config,
32 ...
33 }: let
34 # Port of home-manager's programs.gpg
35 # See https://github.com/nix-community/home-manager/blob/c53d643b3737e2fcd04e6cb3b3580ef50b2087a0/modules/programs/gpg.nix
36 gpgConfGenerator = value:
37 lib.generators.toKeyValue {
38 mkKeyValue = key: v:
39 if lib.isString v
40 then "${key} ${v}"
41 else lib.optionalString v key;
42 listsAsDuplicateKeys = true;
43 }
44 value;
45
46 publicKeys =
47 (map (key: {
48 trust = 5;
49 source =
50 if builtins.isPath key
51 then key
52 else pkgs.writeText "gpg-pubkey" key;
53 })
54 user.identity.gpgKeys)
55 ++ [
56 ];
57
58 gpg = "${pkgs.gnupg}/bin/gpg";
59
60 # Mirror home-manager's mutableKeys/mutableTrust: import managed keys
61 # into the live keyring instead of linking a store keyring.
62 importTrustBashFunctions = ''
63 function gpgKeyId() {
64 ${gpg} --show-key --with-colons "$1" \
65 | grep ^pub: \
66 | cut -d: -f5
67 }
68
69 function importTrust() {
70 local keyIds trust
71 mapfile -t keyIds <<< "$(gpgKeyId "$1")"
72 trust="$2"
73 for id in "''${keyIds[@]}"; do
74 { echo trust; echo "$trust"; (( trust == 5 )) && echo y; echo quit; } \
75 | ${gpg} --no-tty --command-fd 0 --edit-key "$id"
76 done
77 }
78 '';
79
80 importKey = {
81 source,
82 trust,
83 ...
84 }: ''
85 ${gpg} --quiet --import ${source}
86 ${lib.optionalString (trust != null) ''importTrust "${source}" ${toString trust}''}
87 '';
88
89 importKeys = lib.concatMapStringsSep "\n" importKey publicKeys;
90
91 gnupgHome = "${config.directory}/.gnupg";
92 in {
93 packages = [pkgs.gnupg];
94
95 environment.sessionVariables.GNUPGHOME = gnupgHome;
96
97 systemd.services = lib.optionalAttrs (publicKeys != []) {
98 gpg-import-keys = {
99 description = "Import managed GnuPG public keys into the mutable keyring";
100
101 wantedBy = ["default.target"];
102 restartTriggers = map (key: key.source) publicKeys;
103 path = [pkgs.gnupg pkgs.coreutils];
104
105 serviceConfig = {
106 Type = "oneshot";
107 RemainAfterExit = true;
108 };
109
110 script = ''
111 GNUPGHOME=${lib.escapeShellArg gnupgHome}
112 export GNUPGHOME
113 mkdir -m 0700 -p "$GNUPGHOME"
114
115 ${importTrustBashFunctions}
116 ${importKeys}
117 '';
118 };
119 };
120
121 files = {
122 # Based on https://blog.eleven-labs.com/en/openpgp-almost-perfect-key-pair-part-1
123 ".gnupg/gpg.conf" = {
124 generator = gpgConfGenerator;
125 value = {
126 # Get rid of the copyright notice
127 no-greeting = true;
128
129 # --- Avoid information leaked --- #
130 # Disable inclusion of the version string in ASCII armored output
131 no-emit-version = true;
132 # Do not write comment packets
133 no-comments = false;
134 # Export the smallest key possible
135 # This removes all signatures except the most recent self-signature on each user ID
136 export-options = "export-minimal";
137
138 # Display long key IDs
139 keyid-format = "0xlong";
140 # List all keys (or the specified ones) along with their fingerprints
141 with-fingerprint = true;
142
143 # Display the calculated validity of user IDs during key listings
144 list-options = "show-uid-validity";
145 verify-options = "show-uid-validity show-keyserver-urls";
146
147 # Select the strongest cipher
148 personal-cipher-preferences = "AES256";
149 # Select the strongest digest
150 personal-digest-preferences = "SHA512";
151 # This preference list is used for new keys and becomes the default for "setpref" in the edit menu
152 default-preference-list = "SHA512 SHA384 SHA256 RIPEMD160 AES256 TWOFISH BLOWFISH ZLIB BZIP2 ZIP Uncompressed";
153
154 # Use the strongest cipher algorithm
155 cipher-algo = "AES256";
156 # Use the strongest digest algorithm
157 digest-algo = "SHA512";
158 # Message digest algorithm used when signing a key
159 cert-digest-algo = "SHA512";
160 # Use RFC-1950 ZLIB compression
161 compress-algo = "ZLIB";
162
163 # Disable weak algorithm
164 disable-cipher-algo = "3DES";
165 # Treat the specified digest algorithm as weak
166 weak-digest = "SHA1";
167
168 # The cipher algorithm for symmetric encryption for symmetric encryption with a passphrase
169 s2k-cipher-algo = "AES256";
170 # The digest algorithm used to mangle the passphrases for symmetric encryption
171 s2k-digest-algo = "SHA512";
172 # Selects how passphrases for symmetric encryption are mangled
173 s2k-mode = "3";
174 # Specify how many times the passphrases mangling for symmetric encryption is repeated
175 s2k-count = "65011712";
176 };
177 };
178 };
179 };
180 };
181 };
182}