/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

First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

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 © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
5
# Copyright © 2008 Teddy Hogeborn
 
6
# Copyright © 2008 Björn Påhlsson
6
7
7
8
# This program is free software: you can redistribute it and/or modify
8
9
# it under the terms of the GNU General Public License as published by
20
21
# Contact the authors at <mandos@fukt.bsnet.se>.
21
22
22
23
 
23
 
VERSION="1.0"
 
24
VERSION="1.0.2"
24
25
 
25
 
KEYDIR="/etc/mandos"
 
26
KEYDIR="/etc/keys/mandos"
26
27
KEYTYPE=DSA
27
 
KEYLENGTH=1024
28
 
KEYNAME="`hostname --fqdn`"
 
28
KEYLENGTH=2048
 
29
SUBKEYTYPE=ELG-E
 
30
SUBKEYLENGTH=2048
 
31
KEYNAME="`hostname --fqdn 2>/dev/null || hostname`"
29
32
KEYEMAIL=""
30
33
KEYCOMMENT="Mandos client key"
31
34
KEYEXPIRE=0
32
35
FORCE=no
33
36
KEYCOMMENT_ORIG="$KEYCOMMENT"
 
37
mode=keygen
 
38
 
 
39
if [ ! -d "$KEYDIR" ]; then
 
40
    KEYDIR="/etc/mandos/keys"
 
41
fi
34
42
 
35
43
# Parse options
36
 
TEMP=`getopt --options vhd:t:l:n:e:c:x:f \
37
 
    --longoptions version,help,dir:,type:,length:,name:,email:,comment:,expire:,force \
 
44
TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:f \
 
45
    --longoptions version,help,password,passfile:,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,force \
38
46
    --name "$0" -- "$@"`
39
47
 
40
48
help(){
 
49
basename="`basename $0`"
41
50
cat <<EOF
42
 
Usage: `basename $0` [options]
 
51
Usage: $basename [ -v | --version ]
 
52
       $basename [ -h | --help ]
 
53
   Key creation:
 
54
       $basename [ OPTIONS ]
 
55
   Encrypted password creation:
 
56
       $basename { -p | --password } [ --name NAME ] [ --dir DIR]
 
57
       $basename { -F | --passfile } FILE [ --name NAME ] [ --dir DIR]
43
58
 
44
 
Options:
 
59
Key creation options:
45
60
  -v, --version         Show program's version number and exit
46
61
  -h, --help            Show this help message and exit
47
62
  -d DIR, --dir DIR     Target directory for key files
48
63
  -t TYPE, --type TYPE  Key type.  Default is DSA.
49
64
  -l BITS, --length BITS
50
 
                        Key length in bits.  Default is 1024.
 
65
                        Key length in bits.  Default is 2048.
 
66
  -s TYPE, --subtype TYPE
 
67
                        Subkey type.  Default is ELG-E.
 
68
  -L BITS, --sublength BITS
 
69
                        Subkey length in bits.  Default is 2048.
51
70
  -n NAME, --name NAME  Name of key.  Default is the FQDN.
52
 
  -e EMAIL, --email EMAIL
 
71
  -e ADDRESS, --email ADDRESS
53
72
                        Email address of key.  Default is empty.
54
 
  -c COMMENT, --comment COMMENT
 
73
  -c TEXT, --comment TEXT
55
74
                        Comment field for key.  The default value is
56
75
                        "Mandos client key".
57
76
  -x TIME, --expire TIME
58
77
                        Key expire time.  Default is no expiration.
59
78
                        See gpg(1) for syntax.
60
 
  -f, --force           Force overwriting old keys.
 
79
  -f, --force           Force overwriting old key files.
 
80
 
 
81
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.
61
89
EOF
62
90
}
63
91
 
64
92
eval set -- "$TEMP"
65
93
while :; do
66
94
    case "$1" in
 
95
        -p|--password) mode=password; shift;;
 
96
        -F|--passfile) mode=password; PASSFILE="$2"; shift 2;;
67
97
        -d|--dir) KEYDIR="$2"; shift 2;;
68
98
        -t|--type) KEYTYPE="$2"; shift 2;;
 
99
        -s|--subtype) SUBKEYTYPE="$2"; shift 2;;
69
100
        -l|--length) KEYLENGTH="$2"; shift 2;;
 
101
        -L|--sublength) SUBKEYLENGTH="$2"; shift 2;;
70
102
        -n|--name) KEYNAME="$2"; shift 2;;
71
103
        -e|--email) KEYEMAIL="$2"; shift 2;;
72
104
        -c|--comment) KEYCOMMENT="$2"; shift 2;;
73
 
        -x|--expire) KEYCOMMENT="$2"; shift 2;;
 
105
        -x|--expire) KEYEXPIRE="$2"; shift 2;;
74
106
        -f|--force) FORCE=yes; shift;;
75
107
        -v|--version) echo "$0 $VERSION"; exit;;
76
108
        -h|--help) help; exit;;
87
119
PUBKEYFILE="$KEYDIR/pubkey.txt"
88
120
 
89
121
# Check for some invalid values
90
 
if [ -d "$KEYDIR" ]; then :; else
 
122
if [ ! -d "$KEYDIR" ]; then
91
123
    echo "$KEYDIR not a directory" >&2
92
124
    exit 1
93
125
fi
94
 
if [ -w "$KEYDIR" ]; then :; else
95
 
    echo "Directory $KEYDIR not writeable" >&2
96
 
    exit 1
97
 
fi
98
 
 
99
 
if [ -z "$KEYTYPE" ]; then
100
 
    echo "Empty key type" >&2
101
 
    exit 1
102
 
fi
103
 
 
104
 
if [ -z "$KEYNAME" ]; then
105
 
    echo "Empty key name" >&2
106
 
    exit 1
107
 
fi
108
 
 
109
 
if [ -z "$KEYLENGTH" ] || [ "$KEYLENGTH" -lt 512 ]; then
110
 
    echo "Invalid key length" >&2
111
 
    exit 1
112
 
fi
113
 
 
114
 
if [ -z "$KEYEXPIRE" ]; then
115
 
    echo "Empty key expiration" >&2
116
 
    exit 1
117
 
fi
118
 
 
119
 
# Make FORCE be 0 or 1
120
 
case "$FORCE" in
121
 
    [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) FORCE=1;;
122
 
    [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
123
 
esac
124
 
 
125
 
if { [ -e "$SECKEYFILE" ] || [ -e "$PUBKEYFILE" ]; } \
126
 
    && [ "$FORCE" -eq 0 ]; then
127
 
    echo "Refusing to overwrite old key files; use --force" >&2
128
 
    exit 1
129
 
fi
130
 
 
131
 
# Set lines for GnuPG batch file
132
 
if [ -n "$KEYCOMMENT" ]; then
133
 
    KEYCOMMENTLINE="Name-Comment: $KEYCOMMENT"
134
 
fi
135
 
if [ -n "$KEYEMAIL" ]; then
136
 
    KEYEMAILLINE="Name-Email: $KEYEMAIL"
137
 
fi
138
 
 
139
 
# Create temp files
140
 
BATCHFILE="`mktemp -t mandos-gpg-batch.XXXXXXXXXX`"
141
 
SECRING="`mktemp -t mandos-gpg-secring.XXXXXXXXXX`"
142
 
PUBRING="`mktemp -t mandos-gpg-pubring.XXXXXXXXXX`"
 
126
if [ ! -r "$KEYDIR" ]; then
 
127
    echo "Directory $KEYDIR not readable" >&2
 
128
    exit 1
 
129
fi
 
130
 
 
131
if [ "$mode" = keygen ]; then
 
132
    if [ ! -w "$KEYDIR" ]; then
 
133
        echo "Directory $KEYDIR not writeable" >&2
 
134
        exit 1
 
135
    fi
 
136
    if [ -z "$KEYTYPE" ]; then
 
137
        echo "Empty key type" >&2
 
138
        exit 1
 
139
    fi
 
140
    
 
141
    if [ -z "$KEYNAME" ]; then
 
142
        echo "Empty key name" >&2
 
143
        exit 1
 
144
    fi
 
145
    
 
146
    if [ -z "$KEYLENGTH" ] || [ "$KEYLENGTH" -lt 512 ]; then
 
147
        echo "Invalid key length" >&2
 
148
        exit 1
 
149
    fi
 
150
 
 
151
    if [ -z "$KEYEXPIRE" ]; then
 
152
        echo "Empty key expiration" >&2
 
153
        exit 1
 
154
    fi
 
155
    
 
156
    # Make FORCE be 0 or 1
 
157
    case "$FORCE" in
 
158
        [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]) FORCE=1;;
 
159
        [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|*) FORCE=0;;
 
160
    esac
 
161
    
 
162
    if [ \( -e "$SECKEYFILE" -o -e "$PUBKEYFILE" \) \
 
163
        -a "$FORCE" -eq 0 ]; then
 
164
        echo "Refusing to overwrite old key files; use --force" >&2
 
165
        exit 1
 
166
    fi
 
167
    
 
168
    # Set lines for GnuPG batch file
 
169
    if [ -n "$KEYCOMMENT" ]; then
 
170
        KEYCOMMENTLINE="Name-Comment: $KEYCOMMENT"
 
171
    fi
 
172
    if [ -n "$KEYEMAIL" ]; then
 
173
        KEYEMAILLINE="Name-Email: $KEYEMAIL"
 
174
    fi
 
175
 
 
176
    # Create temporary gpg batch file
 
177
    BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
 
178
fi
 
179
 
 
180
if [ "$mode" = password ]; then
 
181
    # Create temporary encrypted password file
 
182
    SECFILE="`mktemp -t mandos-keygen-secfile.XXXXXXXXXX`"
 
183
fi
 
184
 
 
185
# Create temporary key ring directory
 
186
RINGDIR="`mktemp -d -t mandos-keygen-keyrings.XXXXXXXXXX`"
143
187
 
144
188
# Remove temporary files on exit
145
 
trap "rm --force $PUBRING $BATCHFILE; shred --remove $SECRING" EXIT
146
 
 
147
 
# Create batch file for GnuPG
148
 
cat >"$BATCHFILE" <<EOF
149
 
Key-Type: $KEYTYPE
150
 
Key-Length: $KEYLENGTH
151
 
#Key-Usage: encrypt,sign,auth
152
 
Name-Real: $KEYNAME
153
 
$KEYCOMMENTLINE
154
 
$KEYEMAILLINE
155
 
Expire-Date: $KEYEXPIRE
156
 
%pubring $PUBRING
157
 
%secring $SECRING
158
 
%commit
159
 
EOF
160
 
 
161
 
umask 027
162
 
 
163
 
# Generate a new key in the key rings
164
 
gpg --no-random-seed-file --quiet --batch --no-tty \
165
 
    --no-default-keyring --no-options --batch \
166
 
    --secret-keyring "$SECRING" --keyring "$PUBRING" \
167
 
    --gen-key "$BATCHFILE"
168
 
rm --force "$BATCHFILE"
169
 
 
170
 
# Backup any old key files
171
 
if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
172
 
    2>/dev/null; then
173
 
    shred --remove "$SECKEYFILE"
174
 
fi
175
 
if cp --backup=numbered --force "$PUBKEYFILE" "$PUBKEYFILE" \
176
 
    2>/dev/null; then
177
 
    rm --force "$PUBKEYFILE"
178
 
fi
179
 
 
180
 
FILECOMMENT="Mandos client key for $KEYNAME"
181
 
if [ "$KEYCOMMENT" != "$KEYCOMMENT_ORIG" ]; then
182
 
    FILECOMMENT="$FILECOMMENT ($KEYCOMMENT)"
183
 
fi
184
 
 
185
 
if [ -n "$KEYEMAIL" ]; then
186
 
    FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
187
 
fi
188
 
 
189
 
# Export keys from key rings to key files
190
 
gpg --no-random-seed-file --quiet --batch --no-tty --armor \
191
 
    --no-default-keyring --secret-keyring "$SECRING" \
192
 
    --keyring "$PUBRING" --export-options export-minimal \
193
 
    --comment "$FILECOMMENT" --output "$SECKEYFILE" \
194
 
    --export-secret-keys
195
 
gpg --no-random-seed-file --quiet --batch --no-tty --armor \
196
 
    --no-default-keyring --secret-keyring "$SECRING" \
197
 
    --keyring "$PUBRING" --export-options export-minimal \
198
 
    --comment "$FILECOMMENT" --output "$PUBKEYFILE" \
199
 
    --export
 
189
trap "
 
190
set +e; \
 
191
test -n \"$SECFILE\" && shred --remove \"$SECFILE\"; \
 
192
shred --remove \"$RINGDIR\"/sec*;
 
193
test -n \"$BATCHFILE\" && rm --force \"$BATCHFILE\"; \
 
194
rm --recursive --force \"$RINGDIR\";
 
195
stty echo; \
 
196
" EXIT
 
197
 
 
198
umask 077
 
199
 
 
200
if [ "$mode" = keygen ]; then
 
201
    # Create batch file for GnuPG
 
202
    cat >"$BATCHFILE" <<-EOF
 
203
        Key-Type: $KEYTYPE
 
204
        Key-Length: $KEYLENGTH
 
205
        #Key-Usage: encrypt,sign,auth
 
206
        Subkey-Type: $SUBKEYTYPE
 
207
        Subkey-Length: $SUBKEYLENGTH
 
208
        #Subkey-Usage: encrypt,sign,auth
 
209
        Name-Real: $KEYNAME
 
210
        $KEYCOMMENTLINE
 
211
        $KEYEMAILLINE
 
212
        Expire-Date: $KEYEXPIRE
 
213
        #Preferences: <string>
 
214
        #Handle: <no-spaces>
 
215
        #%pubring pubring.gpg
 
216
        #%secring secring.gpg
 
217
        %commit
 
218
        EOF
 
219
    
 
220
    # Generate a new key in the key rings
 
221
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
222
        --homedir "$RINGDIR" --trust-model always \
 
223
        --gen-key "$BATCHFILE"
 
224
    rm --force "$BATCHFILE"
 
225
    
 
226
    # Backup any old key files
 
227
    if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
 
228
        2>/dev/null; then
 
229
        shred --remove "$SECKEYFILE"
 
230
    fi
 
231
    if cp --backup=numbered --force "$PUBKEYFILE" "$PUBKEYFILE" \
 
232
        2>/dev/null; then
 
233
        rm --force "$PUBKEYFILE"
 
234
    fi
 
235
    
 
236
    FILECOMMENT="Mandos client key for $KEYNAME"
 
237
    if [ "$KEYCOMMENT" != "$KEYCOMMENT_ORIG" ]; then
 
238
        FILECOMMENT="$FILECOMMENT ($KEYCOMMENT)"
 
239
    fi
 
240
    
 
241
    if [ -n "$KEYEMAIL" ]; then
 
242
        FILECOMMENT="$FILECOMMENT <$KEYEMAIL>"
 
243
    fi
 
244
    
 
245
    # Export key from key rings to key files
 
246
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
247
        --homedir "$RINGDIR" --armor --export-options export-minimal \
 
248
        --comment "$FILECOMMENT" --output "$SECKEYFILE" \
 
249
        --export-secret-keys
 
250
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
251
        --homedir "$RINGDIR" --armor --export-options export-minimal \
 
252
        --comment "$FILECOMMENT" --output "$PUBKEYFILE" --export
 
253
fi
 
254
 
 
255
if [ "$mode" = password ]; then
 
256
    # Import key into temporary key rings
 
257
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
258
        --homedir "$RINGDIR" --trust-model always --armor \
 
259
        --import "$SECKEYFILE"
 
260
    gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
261
        --homedir "$RINGDIR" --trust-model always --armor \
 
262
        --import "$PUBKEYFILE"
 
263
    
 
264
    # Get fingerprint of key
 
265
    FINGERPRINT="`gpg --quiet --batch --no-tty --no-options \
 
266
        --enable-dsa2 --homedir \"$RINGDIR\" --trust-model always \
 
267
        --fingerprint --with-colons \
 
268
        | sed --quiet \
 
269
        --expression='/^fpr:/{s/^fpr:.*:\\([0-9A-Z]*\\):\$/\\1/p;q}'`"
 
270
    
 
271
    test -n "$FINGERPRINT"
 
272
    
 
273
    FILECOMMENT="Encrypted password for a Mandos client"
 
274
    
 
275
    if [ -n "$PASSFILE" ]; then
 
276
        cat "$PASSFILE"
 
277
    else
 
278
        stty -echo
 
279
        echo -n "Enter passphrase: " >&2
 
280
        first="$(head --lines=1 | tr --delete '\n')"
 
281
        echo -n -e "\nRepeat passphrase: " >&2
 
282
        second="$(head --lines=1 | tr --delete '\n')"
 
283
        echo >&2
 
284
        stty echo
 
285
        if [ "$first" != "$second" ]; then
 
286
            echo -e "Passphrase mismatch" >&2
 
287
            false
 
288
        else
 
289
            echo -n "$first"
 
290
        fi
 
291
    fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
 
292
        --homedir "$RINGDIR" --trust-model always --armor --encrypt \
 
293
        --sign --recipient "$FINGERPRINT" --comment "$FILECOMMENT" \
 
294
        > "$SECFILE"
 
295
    status="${PIPESTATUS[0]}"
 
296
    if [ "$status" -ne 0 ]; then
 
297
        exit "$status"
 
298
    fi
 
299
    
 
300
    cat <<-EOF
 
301
        [$KEYNAME]
 
302
        host = $KEYNAME
 
303
        fingerprint = $FINGERPRINT
 
304
        secret =
 
305
        EOF
 
306
    sed --quiet --expression='
 
307
        /^-----BEGIN PGP MESSAGE-----$/,/^-----END PGP MESSAGE-----$/{
 
308
            /^$/,${
 
309
                # Remove 24-bit Radix-64 checksum
 
310
                s/=....$//
 
311
                # Indent four spaces
 
312
                /^[^-]/s/^/    /p
 
313
            }
 
314
        }' < "$SECFILE"
 
315
fi
200
316
 
201
317
trap - EXIT
202
318
 
 
319
set +e
 
320
# Remove the password file, if any
 
321
if [ -n "$SECFILE" ]; then
 
322
    shred --remove "$SECFILE"
 
323
fi
203
324
# Remove the key rings
204
 
shred --remove "$SECRING"
205
 
rm --force "$PUBRING"
 
325
shred --remove "$RINGDIR"/sec*
 
326
rm --recursive --force "$RINGDIR"