Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/certutil
blob: da1b8d9505fe7deac889a81ff3be4d04a70fef13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#!/bin/sh
#ident $Id$
#
# certutil -- manage trusted X.509 certificates
# inspired by Netscape PKCS #11 toolkit
# contributed by Jarkko Turkulainen <jt@wapit.com>
#
#
# INTRODUCTION
#
#    certutil can be used with various OpenSSL routines and tools
#    that utilize OpenSSL. Example:
#
#    $ openssl s_client -CApath certdir
#
#    where certdir is a directory created by certutil. Other well known
#    programs that use the same format are stunnel, sendmail and pam_ldap
#
#
#
# HOWTO
#
# 1. Initialize certificate database
#
#    Simply by adding a new certificate. If the certificate directory
#    doesn't exist, the script asks for creating a one. Example:
#
#    $ certutil -a -n "First Cert" -i cert.pem -d /home/jt/mycerts
#    ./certutil: cannot access /home/jt/mycerts, create? [y/N] y
#
#
# 2. Add new certificate
#
#    $ certutil -a -n "My Cert" -i cert.pem [-d certdir]
#
#    Note that nickname (-n) must exist. certdir is optional - if it's
#    not given, $PWD is used. The directory must have a file named certs.dat.
#    If that file doesn't exist, the script refuses to do anything. If your
#    certs.dat file is corrupted, "rm -rf" the whole dir and start from
#    the scratch. cert.pem is the actual sertificate.
#
# 3. Delete certificate
#
#    $ certutil -r -n "My Cert" [-d certdir]
#
#    This command removes the certificate named "My Cert". certdir is
#    optional, see 2.
#
# 4. List sertificates
#
#    $ certutil -l [-d certdir]
#
#    And again, certdir is optional.
#
# 5. View certificate properties
#
#    $ certutil -v -n "My Cert" [-d certdir]
#
#


# Print usage
usage() {
        cat << EOF

Usage: $0 -l [-d dir]
          -a -n name -i file [-d dir]
          -r -n name [-d dir]
          -v -n name [-d dir]

       Commands:
          -l   -- List sertificates (requires a valid dir)
          -a   -- Add sertificate and create dir if necessary
          -r   -- Remove sertificate (requires a valid dir)
          -v   -- View sertificate (requires a valid dir)

       Parameters:
          dir  -- Certificate directory, or \$PWD if not given
          name -- Nickname of the certificate
          file -- Certificate file in PEM format

EOF
        exit 1
}

# Check path
check_path() {

        # check the directory
        if [ ! -d $CDIR -a $ADD -eq 1 ]; then
                echo -n "$0: cannot access $CDIR, create? [y/N] "
                read LINE
                case $LINE in
                        y|Y)
                                mkdir $CDIR
                                chmod 700 $CDIR
                                touch $CDIR/certs.dat
                                chmod 600 $CDIR/certs.dat
                                ;;
                        *)
                                exit 1
                                ;;
                esac
        fi

        # check certs.dat
        if [ ! -e $CDIR/certs.dat ]; then
                echo "$0: please specify a valid cert directory"
                exit 1
        fi
}

# Add certificates
add_cert() {
        check_path
        if [ ! -e $FILE ]; then
                echo "$0: cannot find $FILE"
                exit 1
        fi
        HASH=`openssl x509 -in $FILE -hash -noout 2>/dev/null`.0
        if [ $? -ne 0 ]; then
                echo "$0: unable to load certificate $FILE"
                exit 1
        fi

        if grep "^$CNAME|" $CDIR/certs.dat 1>/dev/null 2>&1; then
                echo "$0: nickname already in use"
                exit 1
        fi

        if [ -e $CDIR/$HASH ]; then
                echo "$0: certificate already in directory"
                echo `openssl x509 -in $CDIR/$HASH -subject -noout`
                exit 1
        else
                cp $FILE $CDIR/$HASH
                chmod 600 $CDIR/$HASH
                echo "$CNAME|$HASH" >> $CDIR/certs.dat
                chmod 600 $CDIR/certs.dat
        fi

}

# List certificates
#
# (this is too slow...)
#
list_cert() {
        check_path
        echo
        echo "Certificates in directory $CDIR"
        echo
        printf "%-30s%s\n" nickname subject/issuer
        echo "----------------------------------------------------------------------------"
        cat $CDIR/certs.dat | while read LINE; do
                NICK=`echo $LINE | cut -d "|" -f 1`
                HASH=`echo $LINE | cut -d "|" -f 2`
                SUBJECT=`openssl x509 -in $CDIR/$HASH -subject -noout`
                ISSUER=`openssl x509 -in $CDIR/$HASH -issuer -noout`
                printf "%-30s%s\n" "$NICK" "$SUBJECT"
                printf "%-30s%s\n\n" "" "$ISSUER"

        done
}

# Remove certificates
remove_cert() {
        check_path
        (
        cat $CDIR/certs.dat | while read LINE; do
                NICK=`echo $LINE | cut -d "|" -f 1`
                HASH=`echo $LINE | cut -d "|" -f 2`
                if [ "$CNAME" = "$NICK" ]; then
                        rm $CDIR/$HASH
                else
                        echo $LINE
                fi
        done
        ) > /tmp/$$
        mv /tmp/$$ $CDIR/certs.dat
        chmod 600 $CDIR/certs.dat
}

# View certificate
view_cert() {
        check_path
        cat $CDIR/certs.dat | while read LINE; do
                NICK=`echo $LINE | cut -d "|" -f 1`
                HASH=`echo $LINE | cut -d "|" -f 2`
                if [ "$CNAME" = "$NICK" ]; then
                        openssl x509 -in $CDIR/$HASH -text
                        return 1
                fi
        done
}

# Parse option string
ADD=0
REMOVE=0
LIST=0
VIEW=0
while getopts "arlvd:n:i:" OPT; do
        case $OPT in
                a)
                        ADD=1
                        ;;
                r)
                        REMOVE=1
                        ;;
                l)
                        LIST=1
                        ;;
                v)
                        VIEW=1
                        ;;
                d)
                        CDIR=$OPTARG
                        ;;
                n)
                        CNAME=$OPTARG
                        ;;
                i)
                        FILE=$OPTARG
                        ;;
                *)
                        usage
                        ;;
        esac
done

# Default options
CDIR=${CDIR:=.}

# Check command line options
if [ $ADD -eq 1 -a $REMOVE -eq 0 -a $LIST -eq 0 -a $VIEW -eq 0 ]; then
        if [ -n "$CNAME" -a -n "$FILE" ]; then
                add_cert
        else
                echo "$0: missing certificate name or file"
                usage
        fi
elif [ $REMOVE -eq 1 -a $ADD -eq 0 -a $LIST -eq 0 -a $VIEW -eq 0 ]; then
        if [ -n "$CNAME" ]; then
                remove_cert
        else
                echo "$0: missing certificate name"
                usage
        fi
elif [ $LIST -eq 1 -a $ADD -eq 0 -a $REMOVE -eq 0 -a $VIEW -eq 0 ]; then
        list_cert
elif [ $VIEW -eq 1 -a $ADD -eq 0 -a $REMOVE -eq 0 -a $LIST -eq 0 ]; then
        if [ -n "$CNAME" ]; then
                if view_cert; then
                        echo "$0: cert named \"$CNAME\" not found"
                        exit 1
                fi
        else
                echo "$0: missing certificate name"
                usage
        fi
else
        usage
fi