/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-2015 Teddy Hogeborn
6
 
# Copyright © 2008-2015 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.6.9"
 
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
 
212
        %pubring $PUBRING
 
213
        %secring $SECRING
221
214
        %commit
222
215
        EOF
223
216
    
224
 
    if tty --quiet; then
225
 
        cat <<-EOF
226
 
        Note: Due to entropy requirements, key generation could take
227
 
        anything from a few minutes to SEVERAL HOURS.  Please be
228
 
        patient and/or supply the system with more entropy if needed.
229
 
        EOF
230
 
        echo -n "Started: "
231
 
        date
232
 
    fi
233
 
    
234
 
    # Make sure trustdb.gpg exists;
235
 
    # this is a workaround for Debian bug #737128
236
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
237
 
        --homedir "$RINGDIR" \
238
 
        --import-ownertrust < /dev/null
239
217
    # Generate a new key in the key rings
240
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
241
 
        --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" \
242
221
        --gen-key "$BATCHFILE"
243
222
    rm --force "$BATCHFILE"
244
 
    
245
 
    if tty --quiet; then
246
 
        echo -n "Finished: "
247
 
        date
248
 
    fi
249
 
    
 
223
 
250
224
    # Backup any old key files
251
225
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
252
226
        2>/dev/null; then
266
240
        FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
267
241
    fi
268
242
    
269
 
    # Export key from key rings to key files
270
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
271
 
        --homedir "$RINGDIR" --armor --export-options export-minimal \
272
 
        --comment "$FILECOMMENT" --output "$SECKEYFILE" \
273
 
        --export-secret-keys
274
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
275
 
        --homedir "$RINGDIR" --armor --export-options export-minimal \
276
 
        --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
277
254
fi
278
255
 
279
256
if [ "$mode" = password ]; then
280
 
    
281
 
    # Make SSH be 0 or 1
282
 
    case "$SSH" in
283
 
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) SSH=1;;
284
 
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) SSH=0;;
285
 
    esac
286
 
    
287
 
    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
300
 
        done
301
 
    fi
302
 
    
303
 
    # Import key into temporary key rings
304
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
305
 
        --homedir "$RINGDIR" --trust-model always --armor \
306
 
        --import "$SECKEYFILE"
307
 
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
308
 
        --homedir "$RINGDIR" --trust-model always --armor \
309
 
        --import "$PUBKEYFILE"
310
 
    
 
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
 
311
269
    # Get fingerprint of key
312
 
    FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
313
 
        --enable-dsa2 --homedir "$RINGDIR" --trust-model always \
314
 
        --fingerprint --with-colons \
315
 
        | sed --quiet \
316
 
        --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}'`"
317
276
    
318
277
    test -n "$FINGERPRINT"
319
278
    
320
279
    FILECOMMENT="Encrypted password for a Mandos client"
321
280
    
322
 
    while [ ! -s "$SECFILE" ]; do
323
 
        if [ -n "$PASSFILE" ]; then
324
 
            cat "$PASSFILE"
325
 
        else
326
 
            tty --quiet && stty -echo
327
 
            echo -n "Enter passphrase: " >&2
328
 
            read first
329
 
            tty --quiet && echo >&2
330
 
            echo -n "Repeat passphrase: " >&2
331
 
            read second
332
 
            if tty --quiet; then
333
 
                echo >&2
334
 
                stty echo
335
 
            fi
336
 
            if [ "$first" != "$second" ]; then
337
 
                echo "Passphrase mismatch" >&2
338
 
                touch "$RINGDIR"/mismatch
339
 
            else
340
 
                echo -n "$first"
341
 
            fi
342
 
        fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
343
 
            --homedir "$RINGDIR" --trust-model always --armor \
344
 
            --encrypt --sign --recipient "$FINGERPRINT" --comment \
345
 
            "$FILECOMMENT" > "$SECFILE"
346
 
        if [ -e "$RINGDIR"/mismatch ]; then
347
 
            rm --force "$RINGDIR"/mismatch
348
 
            if tty --quiet; then
349
 
                > "$SECFILE"
350
 
            else
351
 
                exit 1
352
 
            fi
353
 
        fi
354
 
    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
355
293
    
356
294
    cat <<-EOF
357
295
        [$KEYNAME]
358
296
        host = $KEYNAME
359
297
        fingerprint = $FINGERPRINT
360
298
        secret =
361
 
        EOF
362
 
    sed --quiet --expression='
 
299
EOF
 
300
    sed -n -e '
363
301
        /^-----BEGIN PGP MESSAGE-----$/,/^-----END PGP MESSAGE-----$/{
364
302
            /^$/,${
365
303
                # Remove 24-bit Radix-64 checksum
368
306
                /^[^-]/s/^/    /p
369
307
            }
370
308
        }' < "$SECFILE"
371
 
    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"'
373
 
        echo "ssh_fingerprint = ${ssh_fingerprint}"
374
 
    fi
375
309
fi
376
310
 
377
311
trap - EXIT
382
316
    shred --remove "$SECFILE"
383
317
fi
384
318
# Remove the key rings
385
 
shred --remove "$RINGDIR"/sec* 2>/dev/null
386
 
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