/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: 2015-03-10 18:03:38 UTC
  • Revision ID: teddy@recompile.se-20150310180338-pcxw6r2qmw9k6br9
Add ":!RSA" to GnuTLS priority string, to disallow non-DHE kx.

If Mandos was somehow made to use a non-ephemeral Diffie-Hellman key
exchange algorithm in the TLS handshake, any saved network traffic
could then be decrypted later if the Mandos client key was obtained.
By default, Mandos uses ephemeral DH key exchanges which does not have
this problem, but a non-ephemeral key exchange algorithm was still
enabled by default.  The simplest solution is to simply turn that off,
which ensures that Mandos will always use ephemeral DH key exchanges.

There is a "PFS" priority string specifier, but we can't use it because:

1. Security-wise, it is a mix between "NORMAL" and "SECURE128" - it
   enables a lot more algorithms than "SECURE256".

2. It is only available since GnuTLS 3.2.4.

Thanks to Andreas Fischer <af@bantuX.org> for reporting this issue.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/bin/sh -e
2
2
3
 
# Mandos key generator - create new keys for a Mandos client
4
 
5
 
# Copyright © 2008-2019 Teddy Hogeborn
6
 
# Copyright © 2008-2019 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
 
3
# Mandos key generator - create a new OpenPGP key for a Mandos client
 
4
 
5
# Copyright © 2008-2014 Teddy Hogeborn
 
6
# Copyright © 2008-2014 Björn Påhlsson
 
7
 
8
# This program is free software: you can redistribute it and/or modify
 
9
# it under the terms of the GNU General Public License as published by
12
10
# the Free Software Foundation, either version 3 of the License, or
13
11
# (at your option) any later version.
14
12
#
15
 
#     Mandos is distributed in the hope that it will be useful, but
16
 
#     WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
#     This program is distributed in the hope that it will be useful,
 
14
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
17
15
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
16
#     GNU General Public License for more details.
19
17
20
18
# You should have received a copy of the GNU General Public License
21
 
# along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
20
23
21
# Contact the authors at <mandos@recompile.se>.
24
22
25
23
 
26
 
VERSION="1.8.14"
 
24
VERSION="1.6.9"
27
25
 
28
26
KEYDIR="/etc/keys/mandos"
29
27
KEYTYPE=RSA
34
32
KEYEMAIL=""
35
33
KEYCOMMENT=""
36
34
KEYEXPIRE=0
37
 
TLS_KEYTYPE=ed25519
38
35
FORCE=no
39
36
SSH=yes
40
37
KEYCOMMENT_ORIG="$KEYCOMMENT"
45
42
fi
46
43
 
47
44
# Parse options
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
TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:fS \
 
46
    --longoptions version,help,password,passfile:,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,force,no-ssh \
50
47
    --name "$0" -- "$@"`
51
48
 
52
49
help(){
64
61
  -v, --version         Show program's version number and exit
65
62
  -h, --help            Show this help message and exit
66
63
  -d DIR, --dir DIR     Target directory for key files
67
 
  -t TYPE, --type TYPE  OpenPGP key type.  Default is RSA.
 
64
  -t TYPE, --type TYPE  Key type.  Default is RSA.
68
65
  -l BITS, --length BITS
69
 
                        OpenPGP key length in bits.  Default is 4096.
 
66
                        Key length in bits.  Default is 4096.
70
67
  -s TYPE, --subtype TYPE
71
 
                        OpenPGP subkey type.  Default is RSA.
 
68
                        Subkey type.  Default is RSA.
72
69
  -L BITS, --sublength BITS
73
 
                        OpenPGP subkey length in bits.  Default 4096.
 
70
                        Subkey length in bits.  Default is 4096.
74
71
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
75
72
  -e ADDRESS, --email ADDRESS
76
 
                        Email address of OpenPGP key.  Default empty.
 
73
                        Email address of key.  Default is empty.
77
74
  -c TEXT, --comment TEXT
78
 
                        Comment field for OpenPGP key.  Default empty.
 
75
                        Comment field for key.  The default is empty.
79
76
  -x TIME, --expire TIME
80
 
                        OpenPGP key expire time.  Default is none.
 
77
                        Key expire time.  Default is no expiration.
81
78
                        See gpg(1) for syntax.
82
 
  -T TYPE, --tls-keytype TYPE
83
 
                        TLS key type.  Default is ed25519.
84
79
  -f, --force           Force overwriting old key files.
85
80
 
86
81
Password creation options:
109
104
        -e|--email) KEYEMAIL="$2"; shift 2;;
110
105
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
111
106
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
112
 
        -T|--tls-keytype) TLS_KEYTYPE="$2"; shift 2;;
113
107
        -f|--force) FORCE=yes; shift;;
114
108
        -S|--no-ssh) SSH=no; shift;;
115
109
        -v|--version) echo "$0 $VERSION"; exit;;
125
119
 
126
120
SECKEYFILE="$KEYDIR/seckey.txt"
127
121
PUBKEYFILE="$KEYDIR/pubkey.txt"
128
 
TLS_PRIVKEYFILE="$KEYDIR/tls-privkey.pem"
129
 
TLS_PUBKEYFILE="$KEYDIR/tls-pubkey.pem"
130
122
 
131
123
# Check for some invalid values
132
124
if [ ! -d "$KEYDIR" ]; then
169
161
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
170
162
    esac
171
163
    
172
 
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ] \
173
 
             || [ -e "$TLS_PRIVKEYFILE" ] \
174
 
             || [ -e "$TLS_PUBKEYFILE" ]; } \
175
 
        && [ "$FORCE" -eq 0 ]; then
 
164
    if [ \( -e "$SECKEYFILE" -o -e "$PUBKEYFILE" \) \
 
165
        -a "$FORCE" -eq 0 ]; then
176
166
        echo "Refusing to overwrite old key files; use --force" >&2
177
167
        exit 1
178
168
    fi
187
177
    
188
178
    # Create temporary gpg batch file
189
179
    BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
190
 
    TLS_PRIVKEYTMP="`mktemp -t mandos-keygen-privkey.XXXXXXXXXX`"
191
180
fi
192
181
 
193
182
if [ "$mode" = password ]; then
202
191
trap "
203
192
set +e; \
204
193
test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
205
 
test -n \"$TLS_PRIVKEYTMP\" && shred --remove \"$TLS_PRIVKEYTMP\"; \
206
194
shred --remove \"$RINGDIR\"/sec* 2>/dev/null;
207
195
test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
208
196
rm --recursive --force \"$RINGDIR\";
230
218
        #Handle: <no-spaces>
231
219
        #%pubring pubring.gpg
232
220
        #%secring secring.gpg
233
 
        %no-protection
234
221
        %commit
235
222
        EOF
236
223
    
243
230
        echo -n "Started: "
244
231
        date
245
232
    fi
246
 
 
247
 
    # Generate TLS private key
248
 
    if certtool --generate-privkey --password='' \
249
 
                --outfile "$TLS_PRIVKEYTMP" --sec-param ultra \
250
 
                --key-type="$TLS_KEYTYPE" --pkcs8 --no-text 2>/dev/null; then
251
 
        
252
 
        # Backup any old key files
253
 
        if cp --backup=numbered --force "$TLS_PRIVKEYFILE" "$TLS_PRIVKEYFILE" \
254
 
              2>/dev/null; then
255
 
            shred --remove "$TLS_PRIVKEYFILE" 2>/dev/null || :
256
 
        fi
257
 
        if cp --backup=numbered --force "$TLS_PUBKEYFILE" "$TLS_PUBKEYFILE" \
258
 
              2>/dev/null; then
259
 
            rm --force "$TLS_PUBKEYFILE"
260
 
        fi
261
 
        cp --archive "$TLS_PRIVKEYTMP" "$TLS_PRIVKEYFILE"
262
 
        shred --remove "$TLS_PRIVKEYTMP" 2>/dev/null || :
263
 
 
264
 
        ## TLS public key
265
 
 
266
 
        # First try certtool from GnuTLS
267
 
        if ! certtool --password='' --load-privkey="$TLS_PRIVKEYFILE" \
268
 
             --outfile="$TLS_PUBKEYFILE" --pubkey-info --no-text \
269
 
             2>/dev/null; then
270
 
            # Otherwise try OpenSSL
271
 
            if ! openssl pkey -in "$TLS_PRIVKEYFILE" \
272
 
                 -out "$TLS_PUBKEYFILE" -pubout; then
273
 
                rm --force "$TLS_PUBKEYFILE"
274
 
                # None of the commands succeded; give up
275
 
                return 1
276
 
            fi
277
 
        fi
278
 
    fi
279
233
    
280
234
    # Make sure trustdb.gpg exists;
281
235
    # this is a workaround for Debian bug #737128
296
250
    # Backup any old key files
297
251
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
298
252
        2>/dev/null; then
299
 
        shred --remove "$SECKEYFILE" 2>/dev/null || :
 
253
        shred --remove "$SECKEYFILE"
300
254
    fi
301
255
    if cp --backup=numbered --force "$PUBKEYFILE" "$PUBKEYFILE" \
302
256
        2>/dev/null; then
331
285
    esac
332
286
    
333
287
    if [ $SSH -eq 1 ]; then
334
 
        for ssh_keytype in ecdsa-sha2-nistp256 ed25519 rsa; do
335
 
            set +e
336
 
            ssh_fingerprint="`ssh-keyscan -t $ssh_keytype localhost 2>/dev/null`"
337
 
            err=$?
338
 
            set -e
339
 
            if [ $err -ne 0 ]; then
340
 
                ssh_fingerprint=""
341
 
                continue
342
 
            fi
343
 
            if [ -n "$ssh_fingerprint" ]; then
344
 
                ssh_fingerprint="${ssh_fingerprint#localhost }"
345
 
                break
346
 
            fi
347
 
        done
 
288
        set +e
 
289
        ssh_fingerprint="`ssh-keyscan localhost 2>/dev/null`"
 
290
        if [ $? -ne 0 ]; then
 
291
            ssh_fingerprint=""
 
292
        fi
 
293
        set -e
 
294
        ssh_fingerprint="${ssh_fingerprint#localhost }"
348
295
    fi
349
296
    
350
297
    # Import key into temporary key rings
364
311
    
365
312
    test -n "$FINGERPRINT"
366
313
    
367
 
    if [ -r "$TLS_PUBKEYFILE" ]; then
368
 
       KEY_ID="$(certtool --key-id --hash=sha256 \
369
 
                       --infile="$TLS_PUBKEYFILE" 2>/dev/null || :)"
370
 
 
371
 
       if [ -z "$KEY_ID" ]; then
372
 
           KEY_ID=$(openssl pkey -pubin -in "$TLS_PUBKEYFILE" \
373
 
                            -outform der \
374
 
                        | openssl sha256 \
375
 
                        | sed --expression='s/^.*[^[:xdigit:]]//')
376
 
       fi
377
 
       test -n "$KEY_ID"
378
 
    fi
379
 
    
380
314
    FILECOMMENT="Encrypted password for a Mandos client"
381
315
    
382
316
    while [ ! -s "$SECFILE" ]; do
383
317
        if [ -n "$PASSFILE" ]; then
384
 
            cat -- "$PASSFILE"
 
318
            cat "$PASSFILE"
385
319
        else
386
320
            tty --quiet && stty -echo
387
 
            echo -n "Enter passphrase: " >/dev/tty
388
 
            read -r first
 
321
            echo -n "Enter passphrase: " >&2
 
322
            read first
389
323
            tty --quiet && echo >&2
390
 
            echo -n "Repeat passphrase: " >/dev/tty
391
 
            read -r second
 
324
            echo -n "Repeat passphrase: " >&2
 
325
            read second
392
326
            if tty --quiet; then
393
327
                echo >&2
394
328
                stty echo
397
331
                echo "Passphrase mismatch" >&2
398
332
                touch "$RINGDIR"/mismatch
399
333
            else
400
 
                printf "%s" "$first"
 
334
                echo -n "$first"
401
335
            fi
402
336
        fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
403
337
            --homedir "$RINGDIR" --trust-model always --armor \
416
350
    cat <<-EOF
417
351
        [$KEYNAME]
418
352
        host = $KEYNAME
419
 
        EOF
420
 
    if [ -n "$KEY_ID" ]; then
421
 
        echo "key_id = $KEY_ID"
422
 
    fi
423
 
    cat <<-EOF
424
353
        fingerprint = $FINGERPRINT
425
354
        secret =
426
355
        EOF
434
363
            }
435
364
        }' < "$SECFILE"
436
365
    if [ -n "$ssh_fingerprint" ]; then
437
 
        echo 'checker = ssh-keyscan -t '"$ssh_keytype"' %%(host)s 2>/dev/null | grep --fixed-strings --line-regexp --quiet --regexp=%%(host)s" %(ssh_fingerprint)s"'
 
366
        echo 'checker = ssh-keyscan %%(host)s 2>/dev/null | grep --fixed-strings --line-regexp --quiet --regexp=%%(host)s" %(ssh_fingerprint)s"'
438
367
        echo "ssh_fingerprint = ${ssh_fingerprint}"
439
368
    fi
440
369
fi
444
373
set +e
445
374
# Remove the password file, if any
446
375
if [ -n "$SECFILE" ]; then
447
 
    shred --remove "$SECFILE" 2>/dev/null
 
376
    shred --remove "$SECFILE"
448
377
fi
449
378
# Remove the key rings
450
379
shred --remove "$RINGDIR"/sec* 2>/dev/null