/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: 2008-08-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
3
3
# Mandos key generator - create a new OpenPGP key for a Mandos client
4
4
5
 
# Copyright © 2008-2018 Teddy Hogeborn
6
 
# Copyright © 2008-2018 Björn Påhlsson
 
5
# Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
7
6
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
 
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
12
9
# the Free Software Foundation, either version 3 of the License, or
13
10
# (at your option) any later version.
14
11
#
15
 
#     Mandos is distributed in the hope that it will be useful, but
16
 
#     WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#     This program is distributed in the hope that it will be useful,
 
13
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
17
14
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
15
#     GNU General Public License for more details.
19
16
20
17
# You should have received a copy of the GNU General Public License
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.17"
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`"
 
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`"
34
31
KEYEMAIL=""
35
 
KEYCOMMENT=""
 
32
KEYCOMMENT="Mandos client key"
36
33
KEYEXPIRE=0
37
34
FORCE=no
38
 
SSH=yes
39
35
KEYCOMMENT_ORIG="$KEYCOMMENT"
40
36
mode=keygen
41
37
 
42
 
if [ ! -d "$KEYDIR" ]; then
43
 
    KEYDIR="/etc/mandos/keys"
44
 
fi
45
 
 
46
38
# 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 \
 
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 \
49
41
    --name "$0" -- "$@"`
50
42
 
51
43
help(){
52
 
basename="`basename "$0"`"
 
44
basename="`basename $0`"
53
45
cat <<EOF
54
46
Usage: $basename [ -v | --version ]
55
47
       $basename [ -h | --help ]
57
49
       $basename [ OPTIONS ]
58
50
   Encrypted password creation:
59
51
       $basename { -p | --password } [ --name NAME ] [ --dir DIR]
60
 
       $basename { -F | --passfile } FILE [ --name NAME ] [ --dir DIR]
61
52
 
62
53
Key creation options:
63
54
  -v, --version         Show program's version number and exit
64
55
  -h, --help            Show this help message and exit
65
56
  -d DIR, --dir DIR     Target directory for key files
66
 
  -t TYPE, --type TYPE  Key type.  Default is RSA.
 
57
  -t TYPE, --type TYPE  Key type.  Default is DSA.
67
58
  -l BITS, --length BITS
68
 
                        Key length in bits.  Default is 4096.
 
59
                        Key length in bits.  Default is 2048.
69
60
  -s TYPE, --subtype TYPE
70
 
                        Subkey type.  Default is RSA.
 
61
                        Subkey type.  Default is ELG-E.
71
62
  -L BITS, --sublength BITS
72
 
                        Subkey length in bits.  Default is 4096.
 
63
                        Subkey length in bits.  Default is 2048.
73
64
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
74
65
  -e ADDRESS, --email ADDRESS
75
66
                        Email address of key.  Default is empty.
76
 
  -c TEXT, --comment TEXT
77
 
                        Comment field for key.  The default is empty.
 
67
  -c COMMENT, --comment COMMENT
 
68
                        Comment field for key.  The default value is
 
69
                        "Mandos client key".
78
70
  -x TIME, --expire TIME
79
71
                        Key expire time.  Default is no expiration.
80
72
                        See gpg(1) for syntax.
81
 
  -f, --force           Force overwriting old key files.
 
73
  -f, --force           Force overwriting old keys.
82
74
 
83
75
Password creation options:
84
 
  -p, --password        Create an encrypted password using the key in
85
 
                        the key directory.  All options other than
86
 
                        --dir and --name are ignored.
87
 
  -F FILE, --passfile FILE
88
 
                        Encrypt a password from FILE using the key in
89
 
                        the key directory.  All options other than
90
 
                        --dir and --name are ignored.
91
 
  -S, --no-ssh          Don't get SSH key or set "checker" option.
 
76
  -p, --password        Create an encrypted password using the keys in
 
77
                        the key directory.  All options other than
 
78
                        --keydir and --name are ignored.
92
79
EOF
93
80
}
94
81
 
96
83
while :; do
97
84
    case "$1" in
98
85
        -p|--password) mode=password; shift;;
99
 
        -F|--passfile) mode=password; PASSFILE="$2"; shift 2;;
100
86
        -d|--dir) KEYDIR="$2"; shift 2;;
101
87
        -t|--type) KEYTYPE="$2"; shift 2;;
102
88
        -s|--subtype) SUBKEYTYPE="$2"; shift 2;;
107
93
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
108
94
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
109
95
        -f|--force) FORCE=yes; shift;;
110
 
        -S|--no-ssh) SSH=no; shift;;
111
96
        -v|--version) echo "$0 $VERSION"; exit;;
112
97
        -h|--help) help; exit;;
113
98
        --) shift; break;;
115
100
    esac
116
101
done
117
102
if [ "$#" -gt 0 ]; then
118
 
    echo "Unknown arguments: '$*'" >&2
 
103
    echo "Unknown arguments: '$@'" >&2
119
104
    exit 1
120
105
fi
121
106
 
123
108
PUBKEYFILE="$KEYDIR/pubkey.txt"
124
109
 
125
110
# Check for some invalid values
126
 
if [ ! -d "$KEYDIR" ]; then
 
111
if [ -d "$KEYDIR" ]; then :; else
127
112
    echo "$KEYDIR not a directory" >&2
128
113
    exit 1
129
114
fi
130
 
if [ ! -r "$KEYDIR" ]; then
131
 
    echo "Directory $KEYDIR not readable" >&2
 
115
if [ -w "$KEYDIR" ]; then :; else
 
116
    echo "Directory $KEYDIR not writeable" >&2
 
117
    exit 1
 
118
fi
 
119
 
 
120
if [ "$mode" = password -a -e "$KEYDIR/trustdb.gpg.lock" ]; then
 
121
    echo "Key directory has locked trustdb; aborting." >&2
132
122
    exit 1
133
123
fi
134
124
 
135
125
if [ "$mode" = keygen ]; then
136
 
    if [ ! -w "$KEYDIR" ]; then
137
 
        echo "Directory $KEYDIR not writeable" >&2
138
 
        exit 1
139
 
    fi
140
126
    if [ -z "$KEYTYPE" ]; then
141
127
        echo "Empty key type" >&2
142
128
        exit 1
151
137
        echo "Invalid key length" >&2
152
138
        exit 1
153
139
    fi
154
 
    
 
140
 
155
141
    if [ -z "$KEYEXPIRE" ]; then
156
142
        echo "Empty key expiration" >&2
157
143
        exit 1
176
162
    if [ -n "$KEYEMAIL" ]; then
177
163
        KEYEMAILLINE="Name-Email: $KEYEMAIL"
178
164
    fi
179
 
    
 
165
 
180
166
    # Create temporary gpg batch file
181
 
    BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
 
167
    BATCHFILE="`mktemp -t mandos-gpg-batch.XXXXXXXXXX`"
182
168
fi
183
169
 
184
170
if [ "$mode" = password ]; then
185
171
    # Create temporary encrypted password file
186
 
    SECFILE="`mktemp -t mandos-keygen-secfile.XXXXXXXXXX`"
187
 
fi
188
 
 
189
 
# Create temporary key ring directory
190
 
RINGDIR="`mktemp -d -t mandos-keygen-keyrings.XXXXXXXXXX`"
 
172
    SECFILE="`mktemp -t mandos-gpg-secfile.XXXXXXXXXX`"
 
173
fi
 
174
 
 
175
# Create temporary key rings
 
176
SECRING="`mktemp -t mandos-gpg-secring.XXXXXXXXXX`"
 
177
PUBRING="`mktemp -t mandos-gpg-pubring.XXXXXXXXXX`"
 
178
 
 
179
if [ "$mode" = password ]; then
 
180
    # If a trustdb.gpg file does not already exist, schedule it for
 
181
    # deletion when we are done.
 
182
    if ! [ -e "$KEYDIR/trustdb.gpg" ]; then
 
183
        TRUSTDB="$KEYDIR/trustdb.gpg"
 
184
    fi
 
185
fi
191
186
 
192
187
# Remove temporary files on exit
193
188
trap "
194
189
set +e; \
195
 
test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
196
 
shred --remove \"$RINGDIR\"/sec* 2>/dev/null;
197
 
test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
198
 
rm --recursive --force \"$RINGDIR\";
199
 
tty --quiet && stty echo; \
 
190
rm --force $PUBRING ${PUBRING}~ $BATCHFILE $TRUSTDB; \
 
191
shred --remove $SECRING $SECFILE; \
 
192
stty echo; \
200
193
" EXIT
201
194
 
202
 
set -e
203
 
 
204
 
umask 077
 
195
umask 027
205
196
 
206
197
if [ "$mode" = keygen ]; then
207
198
    # Create batch file for GnuPG
208
199
    cat >"$BATCHFILE" <<-EOF
209
200
        Key-Type: $KEYTYPE
210
201
        Key-Length: $KEYLENGTH
211
 
        Key-Usage: sign,auth
 
202
        #Key-Usage: encrypt,sign,auth
212
203
        Subkey-Type: $SUBKEYTYPE
213
204
        Subkey-Length: $SUBKEYLENGTH
214
 
        Subkey-Usage: encrypt
 
205
        #Subkey-Usage: encrypt,sign,auth
215
206
        Name-Real: $KEYNAME
216
207
        $KEYCOMMENTLINE
217
208
        $KEYEMAILLINE
218
209
        Expire-Date: $KEYEXPIRE
219
210
        #Preferences: <string>
220
211
        #Handle: <no-spaces>
221
 
        #%pubring pubring.gpg
222
 
        #%secring secring.gpg
223
 
        %no-protection
 
212
        %pubring $PUBRING
 
213
        %secring $SECRING
224
214
        %commit
225
215
        EOF
226
216
    
227
 
    if tty --quiet; then
228
 
        cat <<-EOF
229
 
        Note: Due to entropy requirements, key generation could take
230
 
        anything from a few minutes to SEVERAL HOURS.  Please be
231
 
        patient and/or supply the system with more entropy if needed.
232
 
        EOF
233
 
        echo -n "Started: "
234
 
        date
235
 
    fi
236
 
    
237
 
    # Make sure trustdb.gpg exists;
238
 
    # this is a workaround for Debian bug #737128
239
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
240
 
        --homedir "$RINGDIR" \
241
 
        --import-ownertrust < /dev/null
242
217
    # Generate a new key in the key rings
243
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
244
 
        --homedir "$RINGDIR" --trust-model always \
 
218
    gpg --no-random-seed-file --quiet --batch --no-tty \
 
219
        --no-default-keyring --no-options --enable-dsa2 \
 
220
        --secret-keyring "$SECRING" --keyring "$PUBRING" \
245
221
        --gen-key "$BATCHFILE"
246
222
    rm --force "$BATCHFILE"
247
 
    
248
 
    if tty --quiet; then
249
 
        echo -n "Finished: "
250
 
        date
251
 
    fi
252
 
    
 
223
 
253
224
    # Backup any old key files
254
225
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
255
226
        2>/dev/null; then
269
240
        FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
270
241
    fi
271
242
    
272
 
    # Export key from key rings to key files
273
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
274
 
        --homedir "$RINGDIR" --armor --export-options export-minimal \
275
 
        --comment "$FILECOMMENT" --output "$SECKEYFILE" \
276
 
        --export-secret-keys
277
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
278
 
        --homedir "$RINGDIR" --armor --export-options export-minimal \
279
 
        --comment "$FILECOMMENT" --output "$PUBKEYFILE" --export
 
243
    # Export keys from key rings to key files
 
244
    gpg --no-random-seed-file --quiet --batch --no-tty --armor \
 
245
        --no-default-keyring --no-options --enable-dsa2 \
 
246
        --secret-keyring "$SECRING" --keyring "$PUBRING" \
 
247
        --export-options export-minimal --comment "$FILECOMMENT" \
 
248
        --output "$SECKEYFILE" --export-secret-keys
 
249
    gpg --no-random-seed-file --quiet --batch --no-tty --armor \
 
250
        --no-default-keyring --no-options --enable-dsa2 \
 
251
        --secret-keyring "$SECRING" --keyring "$PUBRING" \
 
252
        --export-options export-minimal --comment "$FILECOMMENT" \
 
253
        --output "$PUBKEYFILE" --export
280
254
fi
281
255
 
282
256
if [ "$mode" = password ]; then
283
 
    
284
 
    # Make SSH be 0 or 1
285
 
    case "$SSH" in
286
 
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) SSH=1;;
287
 
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) SSH=0;;
288
 
    esac
289
 
    
290
 
    if [ $SSH -eq 1 ]; then
291
 
        for ssh_keytype in ecdsa-sha2-nistp256 ed25519 rsa; do
292
 
            set +e
293
 
            ssh_fingerprint="`ssh-keyscan -t $ssh_keytype localhost 2>/dev/null`"
294
 
            err=$?
295
 
            set -e
296
 
            if [ $err -ne 0 ]; then
297
 
                ssh_fingerprint=""
298
 
                continue
299
 
            fi
300
 
            if [ -n "$ssh_fingerprint" ]; then
301
 
                ssh_fingerprint="${ssh_fingerprint#localhost }"
302
 
                break
303
 
            fi
304
 
        done
305
 
    fi
306
 
    
307
 
    # Import key into temporary key rings
308
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
309
 
        --homedir "$RINGDIR" --trust-model always --armor \
310
 
        --import "$SECKEYFILE"
311
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
312
 
        --homedir "$RINGDIR" --trust-model always --armor \
313
 
        --import "$PUBKEYFILE"
314
 
    
 
257
    # Import keys into temporary key rings
 
258
    gpg --no-random-seed-file --quiet --batch --no-tty --armor \
 
259
        --no-default-keyring --no-options --enable-dsa2 \
 
260
        --homedir "$KEYDIR" --no-permission-warning \
 
261
        --secret-keyring "$SECRING" --keyring "$PUBRING" \
 
262
        --trust-model always --import "$SECKEYFILE"
 
263
    gpg --no-random-seed-file --quiet --batch --no-tty --armor \
 
264
        --no-default-keyring --no-options --enable-dsa2 \
 
265
        --homedir "$KEYDIR" --no-permission-warning \
 
266
        --secret-keyring "$SECRING" --keyring "$PUBRING" \
 
267
        --trust-model always --import "$PUBKEYFILE"
 
268
 
315
269
    # Get fingerprint of key
316
 
    FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
317
 
        --enable-dsa2 --homedir "$RINGDIR" --trust-model always \
318
 
        --fingerprint --with-colons \
319
 
        | sed --quiet \
320
 
        --expression='/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
 
270
    FINGERPRINT="`gpg --no-random-seed-file --quiet --batch --no-tty \
 
271
        --armor --no-default-keyring --no-options --enable-dsa2 \
 
272
        --homedir \"$KEYDIR\" --no-permission-warning \
 
273
        --secret-keyring \"$SECRING\" --keyring \"$PUBRING\" \
 
274
        --trust-model always --fingerprint --with-colons \
 
275
        | sed -n -e '/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
321
276
    
322
277
    test -n "$FINGERPRINT"
323
278
    
324
279
    FILECOMMENT="Encrypted password for a Mandos client"
325
280
    
326
 
    while [ ! -s "$SECFILE" ]; do
327
 
        if [ -n "$PASSFILE" ]; then
328
 
            cat "$PASSFILE"
329
 
        else
330
 
            tty --quiet && stty -echo
331
 
            echo -n "Enter passphrase: " >/dev/tty
332
 
            read -r first
333
 
            tty --quiet && echo >&2
334
 
            echo -n "Repeat passphrase: " >/dev/tty
335
 
            read -r second
336
 
            if tty --quiet; then
337
 
                echo >&2
338
 
                stty echo
339
 
            fi
340
 
            if [ "$first" != "$second" ]; then
341
 
                echo "Passphrase mismatch" >&2
342
 
                touch "$RINGDIR"/mismatch
343
 
            else
344
 
                echo -n "$first"
345
 
            fi
346
 
        fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
347
 
            --homedir "$RINGDIR" --trust-model always --armor \
348
 
            --encrypt --sign --recipient "$FINGERPRINT" --comment \
349
 
            "$FILECOMMENT" > "$SECFILE"
350
 
        if [ -e "$RINGDIR"/mismatch ]; then
351
 
            rm --force "$RINGDIR"/mismatch
352
 
            if tty --quiet; then
353
 
                > "$SECFILE"
354
 
            else
355
 
                exit 1
356
 
            fi
357
 
        fi
358
 
    done
 
281
    stty -echo
 
282
    echo -n "Enter passphrase: " >&2
 
283
    sed -e '1q' \
 
284
        | gpg --no-random-seed-file --batch --no-tty --armor \
 
285
        --no-default-keyring --no-options --enable-dsa2 \
 
286
        --homedir "$KEYDIR" --no-permission-warning \
 
287
        --secret-keyring "$SECRING" --keyring "$PUBRING" \
 
288
        --trust-model always --encrypt --recipient "$FINGERPRINT" \
 
289
        --comment "$FILECOMMENT" \
 
290
        > "$SECFILE"
 
291
    echo >&2
 
292
    stty echo
359
293
    
360
294
    cat <<-EOF
361
295
        [$KEYNAME]
362
296
        host = $KEYNAME
363
297
        fingerprint = $FINGERPRINT
364
298
        secret =
365
 
        EOF
366
 
    sed --quiet --expression='
 
299
EOF
 
300
    sed -n -e '
367
301
        /^-----BEGIN PGP MESSAGE-----$/,/^-----END PGP MESSAGE-----$/{
368
302
            /^$/,${
369
303
                # Remove 24-bit Radix-64 checksum
372
306
                /^[^-]/s/^/    /p
373
307
            }
374
308
        }' < "$SECFILE"
375
 
    if [ -n "$ssh_fingerprint" ]; then
376
 
        echo 'checker = ssh-keyscan -t '"$ssh_keytype"' %%(host)s 2>/dev/null | grep --fixed-strings --line-regexp --quiet --regexp=%%(host)s" %(ssh_fingerprint)s"'
377
 
        echo "ssh_fingerprint = ${ssh_fingerprint}"
378
 
    fi
379
309
fi
380
310
 
381
311
trap - EXIT
386
316
    shred --remove "$SECFILE"
387
317
fi
388
318
# Remove the key rings
389
 
shred --remove "$RINGDIR"/sec* 2>/dev/null
390
 
rm --recursive --force "$RINGDIR"
 
319
shred --remove "$SECRING"
 
320
rm --force "$PUBRING" "${PUBRING}~"
 
321
# Remove the trustdb, if one did not exist when we started
 
322
if [ -n "$TRUSTDB" ]; then
 
323
    rm --force "$TRUSTDB"
 
324
fi