/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/>.
 
21
# along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
19
22
20
 
# Contact the authors at <mandos@fukt.bsnet.se>.
 
23
# Contact the authors at <mandos@recompile.se>.
21
24
22
25
 
23
 
VERSION="1.0"
 
26
VERSION="1.7.20"
24
27
 
25
28
KEYDIR="/etc/keys/mandos"
26
 
KEYTYPE=DSA
27
 
KEYLENGTH=2048
28
 
SUBKEYTYPE=ELG-E
29
 
SUBKEYLENGTH=2048
30
 
KEYNAME="`hostname --fqdn`"
 
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
 
40
45
fi
41
46
 
42
47
# Parse options
43
 
TEMP=`getopt --options vhd:t:l:n:e:c:x:f \
44
 
    --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 \
45
50
    --name "$0" -- "$@"`
46
51
 
47
52
help(){
48
 
basename="`basename $0`"
 
53
basename="`basename "$0"`"
49
54
cat <<EOF
50
55
Usage: $basename [ -v | --version ]
51
56
       $basename [ -h | --help ]
53
58
       $basename [ OPTIONS ]
54
59
   Encrypted password creation:
55
60
       $basename { -p | --password } [ --name NAME ] [ --dir DIR]
 
61
       $basename { -F | --passfile } FILE [ --name NAME ] [ --dir DIR]
56
62
 
57
63
Key creation options:
58
64
  -v, --version         Show program's version number and exit
59
65
  -h, --help            Show this help message and exit
60
66
  -d DIR, --dir DIR     Target directory for key files
61
 
  -t TYPE, --type TYPE  Key type.  Default is DSA.
 
67
  -t TYPE, --type TYPE  OpenPGP key type.  Default is RSA.
62
68
  -l BITS, --length BITS
63
 
                        Key length in bits.  Default is 2048.
 
69
                        OpenPGP key length in bits.  Default is 4096.
64
70
  -s TYPE, --subtype TYPE
65
 
                        Subkey type.  Default is ELG-E.
 
71
                        OpenPGP subkey type.  Default is RSA.
66
72
  -L BITS, --sublength BITS
67
 
                        Subkey length in bits.  Default is 2048.
 
73
                        OpenPGP subkey length in bits.  Default 4096.
68
74
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
69
75
  -e ADDRESS, --email ADDRESS
70
 
                        Email address of key.  Default is empty.
 
76
                        Email address of OpenPGP key.  Default empty.
71
77
  -c TEXT, --comment TEXT
72
 
                        Comment field for key.  The default value is
73
 
                        "Mandos client key".
 
78
                        Comment field for OpenPGP key.  Default empty.
74
79
  -x TIME, --expire TIME
75
 
                        Key expire time.  Default is no expiration.
 
80
                        OpenPGP key expire time.  Default is none.
76
81
                        See gpg(1) for syntax.
77
 
  -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.
78
85
 
79
86
Password creation options:
80
 
  -p, --password        Create an encrypted password using the keys in
81
 
                        the key directory.  All options other than
82
 
                        --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.
83
95
EOF
84
96
}
85
97
 
87
99
while :; do
88
100
    case "$1" in
89
101
        -p|--password) mode=password; shift;;
 
102
        -F|--passfile) mode=password; PASSFILE="$2"; shift 2;;
90
103
        -d|--dir) KEYDIR="$2"; shift 2;;
91
104
        -t|--type) KEYTYPE="$2"; shift 2;;
92
105
        -s|--subtype) SUBKEYTYPE="$2"; shift 2;;
96
109
        -e|--email) KEYEMAIL="$2"; shift 2;;
97
110
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
98
111
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
 
112
        -T|--tls-keytype) TLS_KEYTYPE="$2"; shift 2;;
99
113
        -f|--force) FORCE=yes; shift;;
 
114
        -S|--no-ssh) SSH=no; shift;;
100
115
        -v|--version) echo "$0 $VERSION"; exit;;
101
116
        -h|--help) help; exit;;
102
117
        --) shift; break;;
104
119
    esac
105
120
done
106
121
if [ "$#" -gt 0 ]; then
107
 
    echo "Unknown arguments: '$@'" >&2
 
122
    echo "Unknown arguments: '$*'" >&2
108
123
    exit 1
109
124
fi
110
125
 
111
126
SECKEYFILE="$KEYDIR/seckey.txt"
112
127
PUBKEYFILE="$KEYDIR/pubkey.txt"
 
128
TLS_PRIVKEYFILE="$KEYDIR/tls-privkey.pem"
 
129
TLS_PUBKEYFILE="$KEYDIR/tls-pubkey.pem"
113
130
 
114
131
# Check for some invalid values
115
132
if [ ! -d "$KEYDIR" ]; then
140
157
        echo "Invalid key length" >&2
141
158
        exit 1
142
159
    fi
143
 
 
 
160
    
144
161
    if [ -z "$KEYEXPIRE" ]; then
145
162
        echo "Empty key expiration" >&2
146
163
        exit 1
152
169
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
153
170
    esac
154
171
    
155
 
    if [ \( -e "$SECKEYFILE" -o -e "$PUBKEYFILE" \) \
156
 
        -a "$FORCE" -eq 0 ]; then
 
172
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ] \
 
173
             || [ -e "$TLS_PRIVKEYFILE" ] \
 
174
             || [ -e "$TLS_PUBKEYFILE" ]; } \
 
175
        && [ "$FORCE" -eq 0 ]; then
157
176
        echo "Refusing to overwrite old key files; use --force" >&2
158
177
        exit 1
159
178
    fi
165
184
    if [ -n "$KEYEMAIL" ]; then
166
185
        KEYEMAILLINE="Name-Email: $KEYEMAIL"
167
186
    fi
168
 
 
 
187
    
169
188
    # Create temporary gpg batch file
170
189
    BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
171
190
fi
182
201
trap "
183
202
set +e; \
184
203
test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
185
 
shred --remove \"$RINGDIR\"/sec*;
 
204
shred --remove \"$RINGDIR\"/sec* 2>/dev/null;
186
205
test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
187
206
rm --recursive --force \"$RINGDIR\";
188
 
stty echo; \
 
207
tty --quiet && stty echo; \
189
208
" EXIT
190
209
 
 
210
set -e
 
211
 
191
212
umask 077
192
213
 
193
214
if [ "$mode" = keygen ]; then
195
216
    cat >"$BATCHFILE" <<-EOF
196
217
        Key-Type: $KEYTYPE
197
218
        Key-Length: $KEYLENGTH
198
 
        #Key-Usage: encrypt,sign,auth
 
219
        Key-Usage: sign,auth
199
220
        Subkey-Type: $SUBKEYTYPE
200
221
        Subkey-Length: $SUBKEYLENGTH
201
 
        #Subkey-Usage: encrypt,sign,auth
 
222
        Subkey-Usage: encrypt
202
223
        Name-Real: $KEYNAME
203
224
        $KEYCOMMENTLINE
204
225
        $KEYEMAILLINE
207
228
        #Handle: <no-spaces>
208
229
        #%pubring pubring.gpg
209
230
        #%secring secring.gpg
 
231
        %no-protection
210
232
        %commit
211
233
        EOF
212
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
213
290
    # Generate a new key in the key rings
214
291
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
215
292
        --homedir "$RINGDIR" --trust-model always \
216
293
        --gen-key "$BATCHFILE"
217
294
    rm --force "$BATCHFILE"
218
295
    
 
296
    if tty --quiet; then
 
297
        echo -n "Finished: "
 
298
        date
 
299
    fi
 
300
    
219
301
    # Backup any old key files
220
302
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
221
303
        2>/dev/null; then
235
317
        FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
236
318
    fi
237
319
    
238
 
    # Export keys from key rings to key files
 
320
    # Export key from key rings to key files
239
321
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
240
322
        --homedir "$RINGDIR" --armor --export-options export-minimal \
241
323
        --comment "$FILECOMMENT" --output "$SECKEYFILE" \
246
328
fi
247
329
 
248
330
if [ "$mode" = password ]; then
249
 
    # 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
250
356
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
251
357
        --homedir "$RINGDIR" --trust-model always --armor \
252
358
        --import "$SECKEYFILE"
256
362
    
257
363
    # Get fingerprint of key
258
364
    FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
259
 
        --enable-dsa2 --homedir \"$RINGDIR\" --trust-model always \
 
365
        --enable-dsa2 --homedir "$RINGDIR" --trust-model always \
260
366
        --fingerprint --with-colons \
261
367
        | sed --quiet \
262
368
        --expression='/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
263
369
    
264
370
    test -n "$FINGERPRINT"
265
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
    
266
383
    FILECOMMENT="Encrypted password for a Mandos client"
267
384
    
268
 
    stty -echo
269
 
    echo -n "Enter passphrase: " >&2
270
 
    head --lines=1 | tr --delete '\n' \
271
 
        | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
272
 
        --homedir "$RINGDIR" --trust-model always --armor --encrypt \
273
 
        --recipient "$FINGERPRINT" --comment "$FILECOMMENT" \
274
 
        > "$SECFILE"
275
 
    echo >&2
276
 
    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
277
418
    
278
419
    cat <<-EOF
279
420
        [$KEYNAME]
280
421
        host = $KEYNAME
 
422
        key_id = $KEY_ID
281
423
        fingerprint = $FINGERPRINT
282
424
        secret =
283
 
EOF
 
425
        EOF
284
426
    sed --quiet --expression='
285
427
        /^-----BEGIN PGP MESSAGE-----$/,/^-----END PGP MESSAGE-----$/{
286
428
            /^$/,${
290
432
                /^[^-]/s/^/    /p
291
433
            }
292
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
293
439
fi
294
440
 
295
441
trap - EXIT
300
446
    shred --remove "$SECFILE"
301
447
fi
302
448
# Remove the key rings
303
 
shred --remove "$RINGDIR"/sec*
 
449
shred --remove "$RINGDIR"/sec* 2>/dev/null
304
450
rm --recursive --force "$RINGDIR"