/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos-keygen

  • Committer: Teddy Hogeborn
  • Date: 2019-02-10 03:50:20 UTC
  • Revision ID: teddy@recompile.se-20190210035020-nttr1tybgwwixueu
Show debconf note about new TLS key IDs

If mandos-client did not see TLS keys and had to create them, or if
mandos sees GnuTLS version 3.6.6 or later, show an important notice on
package installation about the importance of adding the new key_id
options to clients.conf on the Mandos server.

* debian/control (Package: mandos, Package: mandos-client): Depend on
                                                            debconf.
* debian/mandos-client.lintian-overrides: Override warnings.
* debian/mandos-client.postinst (create_keys): Show notice if new TLS
                                               key files were created.
* debian/mandos-client.templates: New.
* debian/mandos.lintian-overrides: Override warnings.
* debian/mandos.postinst (configure): If GnuTLS 3.6.6 or later is
                                      detected, show an important
                                      notice (once) about the new
                                      key_id option required in
                                      clients.conf.
* debian/mandos.templates: New.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/bin/sh -e
2
2
3
 
# Mandos key generator - create a new OpenPGP key for a Mandos client
4
 
5
 
# Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
6
 
7
 
# This program is free software: you can redistribute it and/or modify
8
 
# it under the terms of the GNU General Public License as published by
 
3
# Mandos key generator - create new keys for a Mandos client
 
4
 
5
# Copyright © 2008-2018 Teddy Hogeborn
 
6
# Copyright © 2008-2018 Björn Påhlsson
 
7
 
8
# This file is part of Mandos.
 
9
#
 
10
# Mandos is free software: you can redistribute it and/or modify it
 
11
# under the terms of the GNU General Public License as published by
9
12
# the Free Software Foundation, either version 3 of the License, or
10
13
# (at your option) any later version.
11
14
#
12
 
#     This program is distributed in the hope that it will be useful,
13
 
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
#     Mandos is distributed in the hope that it will be useful, but
 
16
#     WITHOUT ANY WARRANTY; without even the implied warranty of
14
17
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
18
#     GNU General Public License for more details.
16
19
17
20
# You should have received a copy of the GNU General Public License
18
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 
20
 
# Contact the authors at <mandos@fukt.bsnet.se>.
21
 
22
 
 
23
 
VERSION="1.0"
24
 
 
25
 
KEYDIR="/etc/mandos"
26
 
KEYTYPE=DSA
27
 
KEYLENGTH=2048
28
 
SUBKEYTYPE=ELG-E
29
 
SUBKEYLENGTH=2048
30
 
KEYNAME="`hostname --fqdn`"
 
21
# along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
22
 
23
# Contact the authors at <mandos@recompile.se>.
 
24
 
25
 
 
26
VERSION="1.7.20"
 
27
 
 
28
KEYDIR="/etc/keys/mandos"
 
29
KEYTYPE=RSA
 
30
KEYLENGTH=4096
 
31
SUBKEYTYPE=RSA
 
32
SUBKEYLENGTH=4096
 
33
KEYNAME="`hostname --fqdn 2>/dev/null || hostname`"
31
34
KEYEMAIL=""
32
 
KEYCOMMENT="Mandos client key"
 
35
KEYCOMMENT=""
33
36
KEYEXPIRE=0
 
37
TLS_KEYTYPE=ed25519
34
38
FORCE=no
 
39
SSH=yes
35
40
KEYCOMMENT_ORIG="$KEYCOMMENT"
36
41
mode=keygen
37
42
 
 
43
if [ ! -d "$KEYDIR" ]; then
 
44
    KEYDIR="/etc/mandos/keys"
 
45
fi
 
46
 
38
47
# Parse options
39
 
TEMP=`getopt --options vhd:t:l:n:e:c:x:f \
40
 
    --longoptions version,help,password,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,force \
 
48
TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:T:fS \
 
49
    --longoptions version,help,password,passfile:,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,tls-keytype:,force,no-ssh \
41
50
    --name "$0" -- "$@"`
42
51
 
43
52
help(){
44
 
basename="`basename $0`"
 
53
basename="`basename "$0"`"
45
54
cat <<EOF
46
55
Usage: $basename [ -v | --version ]
47
56
       $basename [ -h | --help ]
49
58
       $basename [ OPTIONS ]
50
59
   Encrypted password creation:
51
60
       $basename { -p | --password } [ --name NAME ] [ --dir DIR]
 
61
       $basename { -F | --passfile } FILE [ --name NAME ] [ --dir DIR]
52
62
 
53
63
Key creation options:
54
64
  -v, --version         Show program's version number and exit
55
65
  -h, --help            Show this help message and exit
56
66
  -d DIR, --dir DIR     Target directory for key files
57
 
  -t TYPE, --type TYPE  Key type.  Default is DSA.
 
67
  -t TYPE, --type TYPE  OpenPGP key type.  Default is RSA.
58
68
  -l BITS, --length BITS
59
 
                        Key length in bits.  Default is 2048.
 
69
                        OpenPGP key length in bits.  Default is 4096.
60
70
  -s TYPE, --subtype TYPE
61
 
                        Subkey type.  Default is ELG-E.
 
71
                        OpenPGP subkey type.  Default is RSA.
62
72
  -L BITS, --sublength BITS
63
 
                        Subkey length in bits.  Default is 2048.
 
73
                        OpenPGP subkey length in bits.  Default 4096.
64
74
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
65
75
  -e ADDRESS, --email ADDRESS
66
 
                        Email address of key.  Default is empty.
 
76
                        Email address of OpenPGP key.  Default empty.
67
77
  -c TEXT, --comment TEXT
68
 
                        Comment field for key.  The default value is
69
 
                        "Mandos client key".
 
78
                        Comment field for OpenPGP key.  Default empty.
70
79
  -x TIME, --expire TIME
71
 
                        Key expire time.  Default is no expiration.
 
80
                        OpenPGP key expire time.  Default is none.
72
81
                        See gpg(1) for syntax.
73
 
  -f, --force           Force overwriting old keys.
 
82
  -T TYPE, --tls-keytype TYPE
 
83
                        TLS key type.  Default is ed25519.
 
84
  -f, --force           Force overwriting old key files.
74
85
 
75
86
Password creation options:
76
 
  -p, --password        Create an encrypted password using the keys in
77
 
                        the key directory.  All options other than
78
 
                        --dir and --name are ignored.
 
87
  -p, --password        Create an encrypted password using the key in
 
88
                        the key directory.  All options other than
 
89
                        --dir and --name are ignored.
 
90
  -F FILE, --passfile FILE
 
91
                        Encrypt a password from FILE using the key in
 
92
                        the key directory.  All options other than
 
93
                        --dir and --name are ignored.
 
94
  -S, --no-ssh          Don't get SSH key or set "checker" option.
79
95
EOF
80
96
}
81
97
 
83
99
while :; do
84
100
    case "$1" in
85
101
        -p|--password) mode=password; shift;;
 
102
        -F|--passfile) mode=password; PASSFILE="$2"; shift 2;;
86
103
        -d|--dir) KEYDIR="$2"; shift 2;;
87
104
        -t|--type) KEYTYPE="$2"; shift 2;;
88
105
        -s|--subtype) SUBKEYTYPE="$2"; shift 2;;
92
109
        -e|--email) KEYEMAIL="$2"; shift 2;;
93
110
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
94
111
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
 
112
        -T|--tls-keytype) TLS_KEYTYPE="$2"; shift 2;;
95
113
        -f|--force) FORCE=yes; shift;;
 
114
        -S|--no-ssh) SSH=no; shift;;
96
115
        -v|--version) echo "$0 $VERSION"; exit;;
97
116
        -h|--help) help; exit;;
98
117
        --) shift; break;;
100
119
    esac
101
120
done
102
121
if [ "$#" -gt 0 ]; then
103
 
    echo "Unknown arguments: '$@'" >&2
 
122
    echo "Unknown arguments: '$*'" >&2
104
123
    exit 1
105
124
fi
106
125
 
107
126
SECKEYFILE="$KEYDIR/seckey.txt"
108
127
PUBKEYFILE="$KEYDIR/pubkey.txt"
 
128
TLS_PRIVKEYFILE="$KEYDIR/tls-privkey.pem"
 
129
TLS_PUBKEYFILE="$KEYDIR/tls-pubkey.pem"
109
130
 
110
131
# Check for some invalid values
111
132
if [ ! -d "$KEYDIR" ]; then
136
157
        echo "Invalid key length" >&2
137
158
        exit 1
138
159
    fi
139
 
 
 
160
    
140
161
    if [ -z "$KEYEXPIRE" ]; then
141
162
        echo "Empty key expiration" >&2
142
163
        exit 1
148
169
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
149
170
    esac
150
171
    
151
 
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ]; } \
 
172
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ] \
 
173
             || [ -e "$TLS_PRIVKEYFILE" ] \
 
174
             || [ -e "$TLS_PUBKEYFILE" ]; } \
152
175
        && [ "$FORCE" -eq 0 ]; then
153
176
        echo "Refusing to overwrite old key files; use --force" >&2
154
177
        exit 1
161
184
    if [ -n "$KEYEMAIL" ]; then
162
185
        KEYEMAILLINE="Name-Email: $KEYEMAIL"
163
186
    fi
164
 
 
 
187
    
165
188
    # Create temporary gpg batch file
166
189
    BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
167
190
fi
178
201
trap "
179
202
set +e; \
180
203
test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
181
 
shred --remove \"$RINGDIR\"/sec*;
 
204
shred --remove \"$RINGDIR\"/sec* 2>/dev/null;
182
205
test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
183
206
rm --recursive --force \"$RINGDIR\";
184
 
stty echo; \
 
207
tty --quiet && stty echo; \
185
208
" EXIT
186
209
 
187
 
umask 027
 
210
set -e
 
211
 
 
212
umask 077
188
213
 
189
214
if [ "$mode" = keygen ]; then
190
215
    # Create batch file for GnuPG
191
216
    cat >"$BATCHFILE" <<-EOF
192
217
        Key-Type: $KEYTYPE
193
218
        Key-Length: $KEYLENGTH
194
 
        #Key-Usage: encrypt,sign,auth
 
219
        Key-Usage: sign,auth
195
220
        Subkey-Type: $SUBKEYTYPE
196
221
        Subkey-Length: $SUBKEYLENGTH
197
 
        #Subkey-Usage: encrypt,sign,auth
 
222
        Subkey-Usage: encrypt
198
223
        Name-Real: $KEYNAME
199
224
        $KEYCOMMENTLINE
200
225
        $KEYEMAILLINE
203
228
        #Handle: <no-spaces>
204
229
        #%pubring pubring.gpg
205
230
        #%secring secring.gpg
 
231
        %no-protection
206
232
        %commit
207
233
        EOF
208
234
    
 
235
    if tty --quiet; then
 
236
        cat <<-EOF
 
237
        Note: Due to entropy requirements, key generation could take
 
238
        anything from a few minutes to SEVERAL HOURS.  Please be
 
239
        patient and/or supply the system with more entropy if needed.
 
240
        EOF
 
241
        echo -n "Started: "
 
242
        date
 
243
    fi
 
244
    
 
245
    # Backup any old key files
 
246
    if cp --backup=numbered --force "$TLS_PRIVKEYFILE" "$TLS_PRIVKEYFILE" \
 
247
        2>/dev/null; then
 
248
        shred --remove "$TLS_PRIVKEYFILE"
 
249
    fi
 
250
    if cp --backup=numbered --force "$TLS_PUBKEYFILE" "$TLS_PUBKEYFILE" \
 
251
        2>/dev/null; then
 
252
        rm --force "$TLS_PUBKEYFILE"
 
253
    fi
 
254
 
 
255
    ## Generate TLS private key
 
256
 
 
257
    # First try certtool from GnuTLS
 
258
    if ! certtool --generate-privkey --password='' \
 
259
         --outfile "$TLS_PRIVKEYFILE" --sec-param ultra \
 
260
         --key-type="$TLS_KEYTYPE" --pkcs8 --no-text 2>/dev/null; then
 
261
        # Otherwise try OpenSSL
 
262
        if ! openssl genpkey -algorithm X25519 -out \
 
263
             /etc/keys/mandos/tls-privkey.pem; then
 
264
            rm --force /etc/keys/mandos/tls-privkey.pem
 
265
            # None of the commands succeded; give up
 
266
            return 1
 
267
        fi
 
268
    fi
 
269
 
 
270
    ## TLS public key
 
271
 
 
272
    # First try certtool from GnuTLS
 
273
    if ! certtool --password='' --load-privkey="$TLS_PRIVKEYFILE" \
 
274
         --outfile="$TLS_PUBKEYFILE" --pubkey-info --no-text \
 
275
         2>/dev/null; then
 
276
        # Otherwise try OpenSSL
 
277
        if ! openssl pkey -in "$TLS_PRIVKEYFILE" \
 
278
             -out "$TLS_PUBKEYFILE" -pubout; then
 
279
            rm --force "$TLS_PUBKEYFILE"
 
280
            # None of the commands succeded; give up
 
281
            return 1
 
282
        fi
 
283
    fi
 
284
    
 
285
    # Make sure trustdb.gpg exists;
 
286
    # this is a workaround for Debian bug #737128
 
287
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
288
        --homedir "$RINGDIR" \
 
289
        --import-ownertrust < /dev/null
209
290
    # Generate a new key in the key rings
210
291
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
211
292
        --homedir "$RINGDIR" --trust-model always \
212
293
        --gen-key "$BATCHFILE"
213
294
    rm --force "$BATCHFILE"
214
295
    
 
296
    if tty --quiet; then
 
297
        echo -n "Finished: "
 
298
        date
 
299
    fi
 
300
    
215
301
    # Backup any old key files
216
302
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
217
303
        2>/dev/null; then
231
317
        FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
232
318
    fi
233
319
    
234
 
    # Export keys from key rings to key files
 
320
    # Export key from key rings to key files
235
321
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
236
322
        --homedir "$RINGDIR" --armor --export-options export-minimal \
237
323
        --comment "$FILECOMMENT" --output "$SECKEYFILE" \
242
328
fi
243
329
 
244
330
if [ "$mode" = password ]; then
245
 
    # Import keys into temporary key rings
 
331
    
 
332
    # Make SSH be 0 or 1
 
333
    case "$SSH" in
 
334
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) SSH=1;;
 
335
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) SSH=0;;
 
336
    esac
 
337
    
 
338
    if [ $SSH -eq 1 ]; then
 
339
        for ssh_keytype in ecdsa-sha2-nistp256 ed25519 rsa; do
 
340
            set +e
 
341
            ssh_fingerprint="`ssh-keyscan -t $ssh_keytype localhost 2>/dev/null`"
 
342
            err=$?
 
343
            set -e
 
344
            if [ $err -ne 0 ]; then
 
345
                ssh_fingerprint=""
 
346
                continue
 
347
            fi
 
348
            if [ -n "$ssh_fingerprint" ]; then
 
349
                ssh_fingerprint="${ssh_fingerprint#localhost }"
 
350
                break
 
351
            fi
 
352
        done
 
353
    fi
 
354
    
 
355
    # Import key into temporary key rings
246
356
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
247
357
        --homedir "$RINGDIR" --trust-model always --armor \
248
358
        --import "$SECKEYFILE"
252
362
    
253
363
    # Get fingerprint of key
254
364
    FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
255
 
        --enable-dsa2 --homedir \"$RINGDIR\" --trust-model always \
 
365
        --enable-dsa2 --homedir "$RINGDIR" --trust-model always \
256
366
        --fingerprint --with-colons \
257
 
        | sed -n -e '/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
 
367
        | sed --quiet \
 
368
        --expression='/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
258
369
    
259
370
    test -n "$FINGERPRINT"
260
371
    
 
372
    KEY_ID="$(certtool --key-id --hash=sha256 \
 
373
                       --infile="$TLS_PUBKEYFILE" 2>/dev/null || :)"
 
374
 
 
375
    if [ -z "$KEY_ID" ]; then
 
376
        KEY_ID=$(openssl pkey -pubin -in /tmp/tls-pubkey.pem \
 
377
                         -outform der \
 
378
                     | openssl sha256 \
 
379
                     | sed --expression='s/^.*[^[:xdigit:]]//')
 
380
    fi
 
381
    test -n "$KEY_ID"
 
382
    
261
383
    FILECOMMENT="Encrypted password for a Mandos client"
262
384
    
263
 
    stty -echo
264
 
    echo -n "Enter passphrase: " >&2
265
 
    sed -e '1q' \
266
 
        | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
267
 
        --homedir "$RINGDIR" --trust-model always --armor --encrypt \
268
 
        --recipient "$FINGERPRINT" --comment "$FILECOMMENT" \
269
 
        > "$SECFILE"
270
 
    echo >&2
271
 
    stty echo
 
385
    while [ ! -s "$SECFILE" ]; do
 
386
        if [ -n "$PASSFILE" ]; then
 
387
            cat "$PASSFILE"
 
388
        else
 
389
            tty --quiet && stty -echo
 
390
            echo -n "Enter passphrase: " >/dev/tty
 
391
            read -r first
 
392
            tty --quiet && echo >&2
 
393
            echo -n "Repeat passphrase: " >/dev/tty
 
394
            read -r second
 
395
            if tty --quiet; then
 
396
                echo >&2
 
397
                stty echo
 
398
            fi
 
399
            if [ "$first" != "$second" ]; then
 
400
                echo "Passphrase mismatch" >&2
 
401
                touch "$RINGDIR"/mismatch
 
402
            else
 
403
                echo -n "$first"
 
404
            fi
 
405
        fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
406
            --homedir "$RINGDIR" --trust-model always --armor \
 
407
            --encrypt --sign --recipient "$FINGERPRINT" --comment \
 
408
            "$FILECOMMENT" > "$SECFILE"
 
409
        if [ -e "$RINGDIR"/mismatch ]; then
 
410
            rm --force "$RINGDIR"/mismatch
 
411
            if tty --quiet; then
 
412
                > "$SECFILE"
 
413
            else
 
414
                exit 1
 
415
            fi
 
416
        fi
 
417
    done
272
418
    
273
419
    cat <<-EOF
274
420
        [$KEYNAME]
275
421
        host = $KEYNAME
 
422
        key_id = $KEY_ID
276
423
        fingerprint = $FINGERPRINT
277
424
        secret =
278
 
EOF
279
 
    sed -n -e '
 
425
        EOF
 
426
    sed --quiet --expression='
280
427
        /^-----BEGIN PGP MESSAGE-----$/,/^-----END PGP MESSAGE-----$/{
281
428
            /^$/,${
282
429
                # Remove 24-bit Radix-64 checksum
285
432
                /^[^-]/s/^/    /p
286
433
            }
287
434
        }' < "$SECFILE"
 
435
    if [ -n "$ssh_fingerprint" ]; then
 
436
        echo 'checker = ssh-keyscan -t '"$ssh_keytype"' %%(host)s 2>/dev/null | grep --fixed-strings --line-regexp --quiet --regexp=%%(host)s" %(ssh_fingerprint)s"'
 
437
        echo "ssh_fingerprint = ${ssh_fingerprint}"
 
438
    fi
288
439
fi
289
440
 
290
441
trap - EXIT
295
446
    shred --remove "$SECFILE"
296
447
fi
297
448
# Remove the key rings
298
 
shred --remove "$RINGDIR"/sec*
 
449
shred --remove "$RINGDIR"/sec* 2>/dev/null
299
450
rm --recursive --force "$RINGDIR"