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