/mandos/release

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

« back to all changes in this revision

Viewing changes to mandos-keygen

  • Committer: Teddy Hogeborn
  • Date: 2024-09-09 01:36:41 UTC
  • mto: This revision was merged to the branch mainline in revision 410.
  • Revision ID: teddy@recompile.se-20240909013641-6zu6kx2f7meu134k
Make all required directories when installing

When installing into a normal system, one can assume that target
directories, such as /usr/bin, already exists.  But when installing
into a subdirectory for the purpose of creating a package, one cannot
assume that all directories already exist.  Therefore, when
installing, we must not check if any directories exist, and must
instead always create any directories we want to install into.

* Makefile (confdir/mandos.conf, confdir/clients.conf, install-html):
  Use the "-D" option to "install" instead of creating the directory
  separately.
  (install-server): Move creation of $(CONFDIR) down to before it is
  needed.  Don't check if the $(TMPFILES) or $(SYSUSERS) directories
  exist; instead create them by using the "-D" option to "install".
  Create the $(PREFIX)/sbin directory.  Always use
  "--target-directory" if possible; i.e. if the file name is the same.
  Create the $(DBUSPOLICYDIR) and $(DESTDIR)/etc/init.d directories by
  using the "-D" option to "install".  Don't check if the $(SYSTEMD)
  directory exists; instead create it by using the "-D" option to
  "install".  Create the $(DESTDIR)/etc/default and $(MANDIR)/man8
  directories by using the "-D" option to "install".  Create the
  $(MANDIR)/man5 directories explicitly.
  (install-client-nokey): Remove unnecessary creation of the
  $(CONFDIR) directory.  Don't check if the $(SYSUSERS) directory
  exists; instead create it by using the "-D" option to "install".
  Move the "--directory" argument to be the first argument, for
  clarity.  Create the $(PREFIX)/sbin directory.  Use the "-D"
  argument to "install" when installing
  $(INITRAMFSTOOLS)/hooks/mandos,
  $(INITRAMFSTOOLS)/conf.d/mandos-conf,
  $(INITRAMFSTOOLS)/conf-hooks.d/zz-mandos,
  $(INITRAMFSTOOLS)/scripts/init-premount/mandos,
  $(INITRAMFSTOOLS)/scripts/local-premount/mandos,
  $(DRACUTMODULE)/ask-password-mandos.path, and
  $(DRACUTMODULE)/dracut-module/ask-password-mandos.service.  Create
  the $(MANDIR)/man8 directory.

Reported-By: Erich Eckner <erich@eckner.net>
Thanks: Erich Eckner <erich@eckner.net> for analysis

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
 
3
# Mandos key generator - create new keys for a Mandos client
4
4
5
 
# Copyright © 2008-2018 Teddy Hogeborn
6
 
# Copyright © 2008-2018 Björn Påhlsson
 
5
# Copyright © 2008-2019 Teddy Hogeborn
 
6
# Copyright © 2008-2019 Björn Påhlsson
7
7
8
8
# This file is part of Mandos.
9
9
#
23
23
# Contact the authors at <mandos@recompile.se>.
24
24
25
25
 
26
 
VERSION="1.7.18"
 
26
VERSION="1.8.16"
27
27
 
28
28
KEYDIR="/etc/keys/mandos"
29
29
KEYTYPE=RSA
34
34
KEYEMAIL=""
35
35
KEYCOMMENT=""
36
36
KEYEXPIRE=0
 
37
TLS_KEYTYPE=ed25519
37
38
FORCE=no
38
39
SSH=yes
39
40
KEYCOMMENT_ORIG="$KEYCOMMENT"
44
45
fi
45
46
 
46
47
# Parse options
47
 
TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:fS \
48
 
    --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 \
49
50
    --name "$0" -- "$@"`
50
51
 
51
52
help(){
63
64
  -v, --version         Show program's version number and exit
64
65
  -h, --help            Show this help message and exit
65
66
  -d DIR, --dir DIR     Target directory for key files
66
 
  -t TYPE, --type TYPE  Key type.  Default is RSA.
 
67
  -t TYPE, --type TYPE  OpenPGP key type.  Default is RSA.
67
68
  -l BITS, --length BITS
68
 
                        Key length in bits.  Default is 4096.
 
69
                        OpenPGP key length in bits.  Default is 4096.
69
70
  -s TYPE, --subtype TYPE
70
 
                        Subkey type.  Default is RSA.
 
71
                        OpenPGP subkey type.  Default is RSA.
71
72
  -L BITS, --sublength BITS
72
 
                        Subkey length in bits.  Default is 4096.
 
73
                        OpenPGP subkey length in bits.  Default 4096.
73
74
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
74
75
  -e ADDRESS, --email ADDRESS
75
 
                        Email address of key.  Default is empty.
 
76
                        Email address of OpenPGP key.  Default empty.
76
77
  -c TEXT, --comment TEXT
77
 
                        Comment field for key.  The default is empty.
 
78
                        Comment field for OpenPGP key.  Default empty.
78
79
  -x TIME, --expire TIME
79
 
                        Key expire time.  Default is no expiration.
 
80
                        OpenPGP key expire time.  Default is none.
80
81
                        See gpg(1) for syntax.
 
82
  -T TYPE, --tls-keytype TYPE
 
83
                        TLS key type.  Default is ed25519.
81
84
  -f, --force           Force overwriting old key files.
82
85
 
83
86
Password creation options:
106
109
        -e|--email) KEYEMAIL="$2"; shift 2;;
107
110
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
108
111
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
 
112
        -T|--tls-keytype) TLS_KEYTYPE="$2"; shift 2;;
109
113
        -f|--force) FORCE=yes; shift;;
110
114
        -S|--no-ssh) SSH=no; shift;;
111
115
        -v|--version) echo "$0 $VERSION"; exit;;
121
125
 
122
126
SECKEYFILE="$KEYDIR/seckey.txt"
123
127
PUBKEYFILE="$KEYDIR/pubkey.txt"
 
128
TLS_PRIVKEYFILE="$KEYDIR/tls-privkey.pem"
 
129
TLS_PUBKEYFILE="$KEYDIR/tls-pubkey.pem"
124
130
 
125
131
# Check for some invalid values
126
132
if [ ! -d "$KEYDIR" ]; then
141
147
        echo "Empty key type" >&2
142
148
        exit 1
143
149
    fi
144
 
    
 
150
 
145
151
    if [ -z "$KEYNAME" ]; then
146
152
        echo "Empty key name" >&2
147
153
        exit 1
148
154
    fi
149
 
    
 
155
 
150
156
    if [ -z "$KEYLENGTH" ] || [ "$KEYLENGTH" -lt 512 ]; then
151
157
        echo "Invalid key length" >&2
152
158
        exit 1
153
159
    fi
154
 
    
 
160
 
155
161
    if [ -z "$KEYEXPIRE" ]; then
156
162
        echo "Empty key expiration" >&2
157
163
        exit 1
158
164
    fi
159
 
    
 
165
 
160
166
    # Make FORCE be 0 or 1
161
167
    case "$FORCE" in
162
168
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) FORCE=1;;
163
169
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
164
170
    esac
165
 
    
166
 
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ]; } \
 
171
 
 
172
    if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ] \
 
173
             || [ -e "$TLS_PRIVKEYFILE" ] \
 
174
             || [ -e "$TLS_PUBKEYFILE" ]; } \
167
175
        && [ "$FORCE" -eq 0 ]; then
168
176
        echo "Refusing to overwrite old key files; use --force" >&2
169
177
        exit 1
170
178
    fi
171
 
    
 
179
 
172
180
    # Set lines for GnuPG batch file
173
181
    if [ -n "$KEYCOMMENT" ]; then
174
182
        KEYCOMMENTLINE="Name-Comment: $KEYCOMMENT"
176
184
    if [ -n "$KEYEMAIL" ]; then
177
185
        KEYEMAILLINE="Name-Email: $KEYEMAIL"
178
186
    fi
179
 
    
 
187
 
180
188
    # Create temporary gpg batch file
181
189
    BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
 
190
    TLS_PRIVKEYTMP="`mktemp -t mandos-keygen-privkey.XXXXXXXXXX`"
182
191
fi
183
192
 
184
193
if [ "$mode" = password ]; then
193
202
trap "
194
203
set +e; \
195
204
test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
 
205
test -n \"$TLS_PRIVKEYTMP\" && shred --remove \"$TLS_PRIVKEYTMP\"; \
196
206
shred --remove \"$RINGDIR\"/sec* 2>/dev/null;
197
207
test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
198
208
rm --recursive --force \"$RINGDIR\";
223
233
        %no-protection
224
234
        %commit
225
235
        EOF
226
 
    
 
236
 
227
237
    if tty --quiet; then
228
238
        cat <<-EOF
229
239
        Note: Due to entropy requirements, key generation could take
233
243
        echo -n "Started: "
234
244
        date
235
245
    fi
236
 
    
 
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
 
237
280
    # Make sure trustdb.gpg exists;
238
281
    # this is a workaround for Debian bug #737128
239
282
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
244
287
        --homedir "$RINGDIR" --trust-model always \
245
288
        --gen-key "$BATCHFILE"
246
289
    rm --force "$BATCHFILE"
247
 
    
 
290
 
248
291
    if tty --quiet; then
249
292
        echo -n "Finished: "
250
293
        date
251
294
    fi
252
 
    
 
295
 
253
296
    # Backup any old key files
254
297
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
255
298
        2>/dev/null; then
256
 
        shred --remove "$SECKEYFILE"
 
299
        shred --remove "$SECKEYFILE" 2>/dev/null || :
257
300
    fi
258
301
    if cp --backup=numbered --force "$PUBKEYFILE" "$PUBKEYFILE" \
259
302
        2>/dev/null; then
260
303
        rm --force "$PUBKEYFILE"
261
304
    fi
262
 
    
 
305
 
263
306
    FILECOMMENT="Mandos client key for $KEYNAME"
264
307
    if [ "$KEYCOMMENT" != "$KEYCOMMENT_ORIG" ]; then
265
308
        FILECOMMENT="$FILECOMMENT ($KEYCOMMENT)"
266
309
    fi
267
 
    
 
310
 
268
311
    if [ -n "$KEYEMAIL" ]; then
269
312
        FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
270
313
    fi
271
 
    
 
314
 
272
315
    # Export key from key rings to key files
273
316
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
274
317
        --homedir "$RINGDIR" --armor --export-options export-minimal \
280
323
fi
281
324
 
282
325
if [ "$mode" = password ]; then
283
 
    
 
326
 
284
327
    # Make SSH be 0 or 1
285
328
    case "$SSH" in
286
329
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) SSH=1;;
287
330
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) SSH=0;;
288
331
    esac
289
 
    
 
332
 
290
333
    if [ $SSH -eq 1 ]; then
291
334
        for ssh_keytype in ecdsa-sha2-nistp256 ed25519 rsa; do
292
335
            set +e
303
346
            fi
304
347
        done
305
348
    fi
306
 
    
 
349
 
307
350
    # Import key into temporary key rings
308
351
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
309
352
        --homedir "$RINGDIR" --trust-model always --armor \
311
354
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
312
355
        --homedir "$RINGDIR" --trust-model always --armor \
313
356
        --import "$PUBKEYFILE"
314
 
    
 
357
 
315
358
    # Get fingerprint of key
316
359
    FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
317
360
        --enable-dsa2 --homedir "$RINGDIR" --trust-model always \
318
361
        --fingerprint --with-colons \
319
362
        | sed --quiet \
320
363
        --expression='/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
321
 
    
 
364
 
322
365
    test -n "$FINGERPRINT"
323
 
    
 
366
 
 
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
 
324
380
    FILECOMMENT="Encrypted password for a Mandos client"
325
 
    
 
381
 
326
382
    while [ ! -s "$SECFILE" ]; do
327
383
        if [ -n "$PASSFILE" ]; then
328
 
            cat "$PASSFILE"
 
384
            cat -- "$PASSFILE"
329
385
        else
330
386
            tty --quiet && stty -echo
331
387
            echo -n "Enter passphrase: " >/dev/tty
341
397
                echo "Passphrase mismatch" >&2
342
398
                touch "$RINGDIR"/mismatch
343
399
            else
344
 
                echo -n "$first"
 
400
                printf "%s" "$first"
345
401
            fi
346
402
        fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
347
403
            --homedir "$RINGDIR" --trust-model always --armor \
356
412
            fi
357
413
        fi
358
414
    done
359
 
    
 
415
 
360
416
    cat <<-EOF
361
417
        [$KEYNAME]
362
418
        host = $KEYNAME
 
419
        EOF
 
420
    if [ -n "$KEY_ID" ]; then
 
421
        echo "key_id = $KEY_ID"
 
422
    fi
 
423
    cat <<-EOF
363
424
        fingerprint = $FINGERPRINT
364
425
        secret =
365
426
        EOF
383
444
set +e
384
445
# Remove the password file, if any
385
446
if [ -n "$SECFILE" ]; then
386
 
    shred --remove "$SECFILE"
 
447
    shred --remove "$SECFILE" 2>/dev/null
387
448
fi
388
449
# Remove the key rings
389
450
shred --remove "$RINGDIR"/sec* 2>/dev/null