/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: 2024-11-17 18:43:11 UTC
  • Revision ID: teddy@recompile.se-20241117184311-ox25kvngy62h209g
Debian package: Avoid suggesting a C compiler unnecessarily

The list of suggested packages, meant to enable the "mandos" program
to find the correct value of SO_BINDTODEVICE by using a C compiler,
are not necessary when Python 3.3 or later is used, since it has the
SO_BINDTODEVICE constant defined in the "socket" module.  Also, Python
2.6 or older has the same constant in the old "IN" module.  Therefore,
we should suggest these Python versions as alternatives to a C
compiler, so that a C compiler is not installed unnecessarily.

debian/control (Package: mandos/Suggests): Add "python3 (>= 3.3)" and
"python (<= 2.6)" as alternatives to "libc6-dev | libc-dev" and
"c-compiler".

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 © 2008-2015 Teddy Hogeborn
6
 
# Copyright © 2008-2015 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
 
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
10
12
# the Free Software Foundation, either version 3 of the License, or
11
13
# (at your option) any later version.
12
14
#
13
 
#     This program is distributed in the hope that it will be useful,
14
 
#     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
15
17
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
18
#     GNU General Public License for more details.
17
19
18
20
# You should have received a copy of the GNU General Public License
19
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
# along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
20
22
21
23
# Contact the authors at <mandos@recompile.se>.
22
24
23
25
 
24
 
VERSION="1.7.1"
 
26
VERSION="1.8.17"
25
27
 
26
28
KEYDIR="/etc/keys/mandos"
27
29
KEYTYPE=RSA
32
34
KEYEMAIL=""
33
35
KEYCOMMENT=""
34
36
KEYEXPIRE=0
 
37
TLS_KEYTYPE=ed25519
35
38
FORCE=no
36
39
SSH=yes
37
40
KEYCOMMENT_ORIG="$KEYCOMMENT"
42
45
fi
43
46
 
44
47
# Parse options
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 \
 
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 \
47
50
    --name "$0" -- "$@"`
48
51
 
49
52
help(){
61
64
  -v, --version         Show program's version number and exit
62
65
  -h, --help            Show this help message and exit
63
66
  -d DIR, --dir DIR     Target directory for key files
64
 
  -t TYPE, --type TYPE  Key type.  Default is RSA.
 
67
  -t TYPE, --type TYPE  OpenPGP key type.  Default is RSA.
65
68
  -l BITS, --length BITS
66
 
                        Key length in bits.  Default is 4096.
 
69
                        OpenPGP key length in bits.  Default is 4096.
67
70
  -s TYPE, --subtype TYPE
68
 
                        Subkey type.  Default is RSA.
 
71
                        OpenPGP subkey type.  Default is RSA.
69
72
  -L BITS, --sublength BITS
70
 
                        Subkey length in bits.  Default is 4096.
 
73
                        OpenPGP subkey length in bits.  Default 4096.
71
74
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
72
75
  -e ADDRESS, --email ADDRESS
73
 
                        Email address of key.  Default is empty.
 
76
                        Email address of OpenPGP key.  Default empty.
74
77
  -c TEXT, --comment TEXT
75
 
                        Comment field for key.  The default is empty.
 
78
                        Comment field for OpenPGP key.  Default empty.
76
79
  -x TIME, --expire TIME
77
 
                        Key expire time.  Default is no expiration.
 
80
                        OpenPGP key expire time.  Default is none.
78
81
                        See gpg(1) for syntax.
 
82
  -T TYPE, --tls-keytype TYPE
 
83
                        TLS key type.  Default is ed25519.
79
84
  -f, --force           Force overwriting old key files.
80
85
 
81
86
Password creation options:
104
109
        -e|--email) KEYEMAIL="$2"; shift 2;;
105
110
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
106
111
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
 
112
        -T|--tls-keytype) TLS_KEYTYPE="$2"; shift 2;;
107
113
        -f|--force) FORCE=yes; shift;;
108
114
        -S|--no-ssh) SSH=no; shift;;
109
115
        -v|--version) echo "$0 $VERSION"; exit;;
119
125
 
120
126
SECKEYFILE="$KEYDIR/seckey.txt"
121
127
PUBKEYFILE="$KEYDIR/pubkey.txt"
 
128
TLS_PRIVKEYFILE="$KEYDIR/tls-privkey.pem"
 
129
TLS_PUBKEYFILE="$KEYDIR/tls-pubkey.pem"
122
130
 
123
131
# Check for some invalid values
124
132
if [ ! -d "$KEYDIR" ]; then
139
147
        echo "Empty key type" >&2
140
148
        exit 1
141
149
    fi
142
 
    
 
150
 
143
151
    if [ -z "$KEYNAME" ]; then
144
152
        echo "Empty key name" >&2
145
153
        exit 1
146
154
    fi
147
 
    
 
155
 
148
156
    if [ -z "$KEYLENGTH" ] || [ "$KEYLENGTH" -lt 512 ]; then
149
157
        echo "Invalid key length" >&2
150
158
        exit 1
151
159
    fi
152
 
    
 
160
 
153
161
    if [ -z "$KEYEXPIRE" ]; then
154
162
        echo "Empty key expiration" >&2
155
163
        exit 1
156
164
    fi
157
 
    
 
165
 
158
166
    # Make FORCE be 0 or 1
159
167
    case "$FORCE" in
160
168
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) FORCE=1;;
161
169
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
162
170
    esac
163
 
    
164
 
    if [ \( -e "$SECKEYFILE" -o -e "$PUBKEYFILE" \) \
165
 
        -a "$FORCE" -eq 0 ]; then
 
171
 
 
172
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ] \
 
173
             || [ -e "$TLS_PRIVKEYFILE" ] \
 
174
             || [ -e "$TLS_PUBKEYFILE" ]; } \
 
175
        && [ "$FORCE" -eq 0 ]; then
166
176
        echo "Refusing to overwrite old key files; use --force" >&2
167
177
        exit 1
168
178
    fi
169
 
    
 
179
 
170
180
    # Set lines for GnuPG batch file
171
181
    if [ -n "$KEYCOMMENT" ]; then
172
182
        KEYCOMMENTLINE="Name-Comment: $KEYCOMMENT"
174
184
    if [ -n "$KEYEMAIL" ]; then
175
185
        KEYEMAILLINE="Name-Email: $KEYEMAIL"
176
186
    fi
177
 
    
 
187
 
178
188
    # Create temporary gpg batch file
179
189
    BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
 
190
    TLS_PRIVKEYTMP="`mktemp -t mandos-keygen-privkey.XXXXXXXXXX`"
180
191
fi
181
192
 
182
193
if [ "$mode" = password ]; then
191
202
trap "
192
203
set +e; \
193
204
test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
 
205
test -n \"$TLS_PRIVKEYTMP\" && shred --remove \"$TLS_PRIVKEYTMP\"; \
194
206
shred --remove \"$RINGDIR\"/sec* 2>/dev/null;
195
207
test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
196
208
rm --recursive --force \"$RINGDIR\";
218
230
        #Handle: <no-spaces>
219
231
        #%pubring pubring.gpg
220
232
        #%secring secring.gpg
 
233
        %no-protection
221
234
        %commit
222
235
        EOF
223
 
    
 
236
 
224
237
    if tty --quiet; then
225
238
        cat <<-EOF
226
239
        Note: Due to entropy requirements, key generation could take
230
243
        echo -n "Started: "
231
244
        date
232
245
    fi
233
 
    
 
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
 
234
280
    # Make sure trustdb.gpg exists;
235
281
    # this is a workaround for Debian bug #737128
236
282
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
241
287
        --homedir "$RINGDIR" --trust-model always \
242
288
        --gen-key "$BATCHFILE"
243
289
    rm --force "$BATCHFILE"
244
 
    
 
290
 
245
291
    if tty --quiet; then
246
292
        echo -n "Finished: "
247
293
        date
248
294
    fi
249
 
    
 
295
 
250
296
    # Backup any old key files
251
297
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
252
298
        2>/dev/null; then
253
 
        shred --remove "$SECKEYFILE"
 
299
        shred --remove "$SECKEYFILE" 2>/dev/null || :
254
300
    fi
255
301
    if cp --backup=numbered --force "$PUBKEYFILE" "$PUBKEYFILE" \
256
302
        2>/dev/null; then
257
303
        rm --force "$PUBKEYFILE"
258
304
    fi
259
 
    
 
305
 
260
306
    FILECOMMENT="Mandos client key for $KEYNAME"
261
307
    if [ "$KEYCOMMENT" != "$KEYCOMMENT_ORIG" ]; then
262
308
        FILECOMMENT="$FILECOMMENT ($KEYCOMMENT)"
263
309
    fi
264
 
    
 
310
 
265
311
    if [ -n "$KEYEMAIL" ]; then
266
312
        FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
267
313
    fi
268
 
    
 
314
 
269
315
    # Export key from key rings to key files
270
316
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
271
317
        --homedir "$RINGDIR" --armor --export-options export-minimal \
277
323
fi
278
324
 
279
325
if [ "$mode" = password ]; then
280
 
    
 
326
 
281
327
    # Make SSH be 0 or 1
282
328
    case "$SSH" in
283
329
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) SSH=1;;
284
330
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) SSH=0;;
285
331
    esac
286
 
    
 
332
 
287
333
    if [ $SSH -eq 1 ]; then
288
 
        for ssh_keytype in ed25519 rsa; do
289
 
            set +e
290
 
            ssh_fingerprint="`ssh-keyscan -t $ssh_keytype localhost 2>/dev/null`"
291
 
            set -e
292
 
            if [ $? -ne 0 ]; then
293
 
                ssh_fingerprint=""
294
 
                continue
295
 
            fi
296
 
            if [ -n "$ssh_fingerprint" ]; then
297
 
                ssh_fingerprint="${ssh_fingerprint#localhost }"
298
 
                break
299
 
            fi
 
334
        # The -q option is new in OpenSSH 9.8
 
335
        for ssh_keyscan_quiet in "-q " ""; do
 
336
            for ssh_keytype in ecdsa-sha2-nistp256 ed25519 rsa; do
 
337
                set +e
 
338
                ssh_fingerprint="`ssh-keyscan ${ssh_keyscan_quiet}-t $ssh_keytype localhost 2>/dev/null`"
 
339
                err=$?
 
340
                set -e
 
341
                if [ $err -ne 0 ]; then
 
342
                    ssh_fingerprint=""
 
343
                    continue
 
344
                fi
 
345
                if [ -n "$ssh_fingerprint" ]; then
 
346
                    ssh_fingerprint="${ssh_fingerprint#localhost }"
 
347
                    break 2
 
348
                fi
 
349
            done
300
350
        done
301
351
    fi
302
 
    
 
352
 
303
353
    # Import key into temporary key rings
304
354
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
305
355
        --homedir "$RINGDIR" --trust-model always --armor \
307
357
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
308
358
        --homedir "$RINGDIR" --trust-model always --armor \
309
359
        --import "$PUBKEYFILE"
310
 
    
 
360
 
311
361
    # Get fingerprint of key
312
362
    FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
313
363
        --enable-dsa2 --homedir "$RINGDIR" --trust-model always \
314
364
        --fingerprint --with-colons \
315
365
        | sed --quiet \
316
366
        --expression='/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
317
 
    
 
367
 
318
368
    test -n "$FINGERPRINT"
319
 
    
 
369
 
 
370
    if [ -r "$TLS_PUBKEYFILE" ]; then
 
371
       KEY_ID="$(certtool --key-id --hash=sha256 \
 
372
                       --infile="$TLS_PUBKEYFILE" 2>/dev/null || :)"
 
373
 
 
374
       if [ -z "$KEY_ID" ]; then
 
375
           KEY_ID=$(openssl pkey -pubin -in "$TLS_PUBKEYFILE" \
 
376
                            -outform der \
 
377
                        | openssl sha256 \
 
378
                        | sed --expression='s/^.*[^[:xdigit:]]//')
 
379
       fi
 
380
       test -n "$KEY_ID"
 
381
    fi
 
382
 
320
383
    FILECOMMENT="Encrypted password for a Mandos client"
321
 
    
 
384
 
322
385
    while [ ! -s "$SECFILE" ]; do
323
386
        if [ -n "$PASSFILE" ]; then
324
 
            cat "$PASSFILE"
 
387
            cat -- "$PASSFILE"
325
388
        else
326
389
            tty --quiet && stty -echo
327
 
            echo -n "Enter passphrase: " >&2
328
 
            read first
 
390
            echo -n "Enter passphrase: " >/dev/tty
 
391
            read -r first
329
392
            tty --quiet && echo >&2
330
 
            echo -n "Repeat passphrase: " >&2
331
 
            read second
 
393
            echo -n "Repeat passphrase: " >/dev/tty
 
394
            read -r second
332
395
            if tty --quiet; then
333
396
                echo >&2
334
397
                stty echo
337
400
                echo "Passphrase mismatch" >&2
338
401
                touch "$RINGDIR"/mismatch
339
402
            else
340
 
                echo -n "$first"
 
403
                printf "%s" "$first"
341
404
            fi
342
405
        fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
343
406
            --homedir "$RINGDIR" --trust-model always --armor \
352
415
            fi
353
416
        fi
354
417
    done
355
 
    
 
418
 
356
419
    cat <<-EOF
357
420
        [$KEYNAME]
358
421
        host = $KEYNAME
 
422
        EOF
 
423
    if [ -n "$KEY_ID" ]; then
 
424
        echo "key_id = $KEY_ID"
 
425
    fi
 
426
    cat <<-EOF
359
427
        fingerprint = $FINGERPRINT
360
428
        secret =
361
429
        EOF
369
437
            }
370
438
        }' < "$SECFILE"
371
439
    if [ -n "$ssh_fingerprint" ]; then
372
 
        echo 'checker = ssh-keyscan -t '"$ssh_keytype"' %%(host)s 2>/dev/null | grep --fixed-strings --line-regexp --quiet --regexp=%%(host)s" %(ssh_fingerprint)s"'
 
440
        echo 'checker = ssh-keyscan '"$ssh_keyscan_quiet"'-t '"$ssh_keytype"' %%(host)s 2>/dev/null | grep --fixed-strings --line-regexp --quiet --regexp=%%(host)s" %(ssh_fingerprint)s"'
373
441
        echo "ssh_fingerprint = ${ssh_fingerprint}"
374
442
    fi
375
443
fi
379
447
set +e
380
448
# Remove the password file, if any
381
449
if [ -n "$SECFILE" ]; then
382
 
    shred --remove "$SECFILE"
 
450
    shred --remove "$SECFILE" 2>/dev/null
383
451
fi
384
452
# Remove the key rings
385
453
shred --remove "$RINGDIR"/sec* 2>/dev/null